Python SDK API Reference
Complete API reference for the Hawcx Python SDK
Python SDK API Reference
OAuth Exchange
exchange_code_for_claims()
Exchanges a Hawcx authorization code for verified JWT claims.
Parameters:
def exchange_code_for_claims(
code: str, # Authorization code from Hawcx
oauth_token_url: str, # Token endpoint URL
client_id: str, # OAuth client ID
public_key: str | Path, # Public key (PEM string or file path)
code_verifier: str | None = None, # PKCE code verifier (optional)
audience: str | None = None, # Expected 'aud' claim (optional)
issuer: str | None = None, # Expected 'iss' claim (optional)
leeway: int = 0 # Clock skew tolerance in seconds
) -> dict[str, Any]Returns:
{
'sub': str, # Subject (user ID)
'email': str, # User email
'email_verified': bool, # Whether email is verified
'aud': str, # Audience
'iss': str, # Issuer
'iat': int, # Issued at (Unix timestamp)
'exp': int, # Expiration (Unix timestamp)
# ... additional claims
}Raises:
OAuthExchangeError- Failed to exchange code for tokenJWTVerificationError- JWT signature or claims validation failedInvalidPublicKeyError- Public key is malformed
Example:
from hawcx_oauth_client import exchange_code_for_claims
import os
try:
claims = exchange_code_for_claims(
code='auth_code_from_client',
oauth_token_url=os.getenv('OAUTH_TOKEN_ENDPOINT'),
client_id=os.getenv('OAUTH_CLIENT_ID'),
public_key=os.getenv('OAUTH_PUBLIC_KEY'),
audience=os.getenv('OAUTH_CLIENT_ID')
)
print(f'User ID: {claims["sub"]}')
print(f'Email: {claims["email"]}')
except Exception as error:
print(f'Exchange failed: {error}')JWT Verification
verify_jwt()
Manually verify a JWT token using the provided public key.
Parameters:
def verify_jwt(
token: str, # JWT token to verify
public_key: str | Path, # Public key (PEM string or file path)
algorithms: list[str] | None = None, # Allowed algorithms (default: ['RS256'])
audience: str | None = None, # Expected 'aud' claim
issuer: str | None = None, # Expected 'iss' claim
leeway: int = 0 # Clock skew tolerance in seconds
) -> dict[str, Any]Returns:
dict[str, Any] # JWT payloadExample:
from hawcx_oauth_client import verify_jwt
payload = verify_jwt(
token=token,
public_key=public_key,
audience='my-app',
issuer='https://example.hawcx.com'
)Delegation Client
The HawcxDelegationClient provides high-level APIs for managing user MFA settings and credentials.
HawcxDelegationClient.from_keys()
Initialize the delegation client with explicit cryptographic keys.
Parameters:
@classmethod
def from_keys(
cls,
sp_signing_key: str, # Service provider ED25519 private key (PEM)
sp_encryption_key: str, # Service provider X25519 private key (PEM)
idp_verify_key: str, # Identity provider ED25519 public key (PEM)
idp_encryption_key: str, # Identity provider X25519 public key (PEM)
base_url: str | None = None, # Hawcx base URL
sp_id: str | None = None # Service provider ID
) -> HawcxDelegationClientExample:
from hawcx_oauth_client.delegation import HawcxDelegationClient
import os
client = HawcxDelegationClient.from_keys(
sp_signing_key=os.getenv('SP_ED25519_PRIVATE_KEY_PEM'),
sp_encryption_key=os.getenv('SP_X25519_PRIVATE_KEY_PEM'),
idp_verify_key=os.getenv('IDP_ED25519_PUBLIC_KEY_PEM'),
idp_encryption_key=os.getenv('IDP_X25519_PUBLIC_KEY_PEM'),
sp_id=os.getenv('OAUTH_CLIENT_ID')
)initiate_mfa_change()
Initiate MFA setup or change for a user.
Parameters:
def initiate_mfa_change(
self,
userid: str, # User email or ID
mfa_method: MfaMethod, # MFA method (EMAIL, SMS, TOTP)
phone_number: str | None = None # Phone number (required for SMS)
) -> dict[str, Any]MfaMethod Enum:
from hawcx_oauth_client.delegation import MfaMethod
MfaMethod.EMAIL # Email-based MFA
MfaMethod.SMS # SMS-based MFA
MfaMethod.TOTP # Time-based One-Time PasswordReturns:
{
'session_id': str, # Session ID for verification
'status': str,
'message': str | None
}Example:
from hawcx_oauth_client.delegation import HawcxDelegationClient, MfaMethod
client = HawcxDelegationClient.from_env()
result = client.initiate_mfa_change(
userid='[email protected]',
mfa_method=MfaMethod.SMS,
phone_number='+15551234567'
)
print(f'Session ID: {result["session_id"]}')verify_mfa_change()
Verify OTP and complete MFA setup or change.
Parameters:
def verify_mfa_change(
self,
userid: str, # User email or ID
session_id: str, # Session ID from initiate_mfa_change
otp: str # One-time password (6 digits)
) -> dict[str, Any]Returns:
{
'status': str, # 'success' or 'failed'
'message': str | None
}Example:
result = client.verify_mfa_change(
userid='[email protected]',
session_id=session_from_initiate,
otp='123456'
)
if result['status'] == 'success':
print('MFA setup complete!')get_user_credentials()
Retrieve the current MFA method and credentials for a user.
Parameters:
def get_user_credentials(self, userid: str) -> dict[str, Any]Returns:
{
'mfa_method': str, # Current MFA method
'status': str,
'message': str | None
}Example:
creds = client.get_user_credentials('[email protected]')
print(f'Current MFA: {creds["mfa_method"]}')Exception Types
OAuthExchangeError
Thrown when OAuth code exchange fails.
from hawcx_oauth_client import OAuthExchangeError, exchange_code_for_claims
try:
claims = exchange_code_for_claims(...)
except OAuthExchangeError as error:
print(f'OAuth error: {error}')JWTVerificationError
Thrown when JWT signature or claims validation fails.
from hawcx_oauth_client import JWTVerificationError
try:
payload = verify_jwt(token, public_key)
except JWTVerificationError as error:
print(f'JWT verification failed: {error}')InvalidPublicKeyError
Thrown when the provided public key is malformed.
from hawcx_oauth_client import InvalidPublicKeyError, exchange_code_for_claims
try:
claims = exchange_code_for_claims(
code=code,
oauth_token_url=url,
client_id=client_id,
public_key='invalid-key'
)
except InvalidPublicKeyError as error:
print(f'Key format error: {error}')Type Hints
Full type annotations are available:
from hawcx_oauth_client import (
exchange_code_for_claims,
verify_jwt,
OAuthExchangeError,
JWTVerificationError,
InvalidPublicKeyError
)
from hawcx_oauth_client.delegation import (
HawcxDelegationClient,
MfaMethod
)Flask Integration
The SDK provides optional Flask decorators:
from flask import Flask, request, session
from hawcx_oauth_client.flask_helpers import require_hawcx_auth
app = Flask(__name__)
@app.route('/protected', methods=['GET'])
@require_hawcx_auth
def protected_endpoint():
"""Only accessible to authenticated users"""
user_id = session.get('hawcx_user_id')
return {'user_id': user_id}Best Practices
1. Environment Variable Management
from hawcx_oauth_client.delegation import HawcxDelegationClient
import os
# Use environment variables for all sensitive keys
client = HawcxDelegationClient.from_env()2. Error Handling
from hawcx_oauth_client import (
exchange_code_for_claims,
OAuthExchangeError,
JWTVerificationError
)
import os
try:
claims = exchange_code_for_claims(
code=auth_code,
oauth_token_url=os.getenv('OAUTH_TOKEN_ENDPOINT'),
client_id=os.getenv('OAUTH_CLIENT_ID'),
public_key=os.getenv('OAUTH_PUBLIC_KEY')
)
except OAuthExchangeError as e:
# Handle OAuth errors (invalid code, expired, etc.)
print(f'OAuth error: {e}')
except JWTVerificationError as e:
# Handle JWT validation errors
print(f'JWT error: {e}')3. Clock Skew Tolerance
For distributed systems, add clock skew tolerance:
claims = exchange_code_for_claims(
code=auth_code,
oauth_token_url=token_endpoint,
client_id=client_id,
public_key=public_key,
leeway=10 # Allow 10 seconds of clock skew
)4. MFA Flow
from hawcx_oauth_client.delegation import MfaMethod
# Step 1: Initiate
mfa_session = client.initiate_mfa_change(
userid='[email protected]',
mfa_method=MfaMethod.SMS,
phone_number='+15551234567'
)
# Step 2: User receives OTP via SMS
# Step 3: Verify
result = client.verify_mfa_change(
userid='[email protected]',
session_id=mfa_session['session_id'],
otp=user_provided_otp
)
if result['status'] == 'success':
# MFA setup complete
pass