API Documentation
/
Backend
/
Python
/
Python Backend SDK Quickstart

Python Backend SDK Quickstart

Integrate Hawcx OAuth authentication in your Python backend

Hawcx OAuth Client SDK for Python

Add passwordless authentication to your Python backend. Exchange authorization codes for verified user claims and manage MFA.

Installation

pip install hawcx-oauth-client

Quick Start

OAuth Code Exchange

The most common flow: exchange authCode + codeVerifier for verified user claims.

from hawcx_oauth_client import HawcxOAuth
from flask import request, jsonify
import os

oauth = HawcxOAuth(
    config_id=os.getenv('HAWCX_API_KEY'),
    base_url=os.getenv('HAWCX_BASE_URL')  # optional
)

@app.route('/exchange', methods=['POST'])
def exchange():
    try:
        data = request.json
        result = oauth.exchange_code(data['authCode'], data['codeVerifier'])
        claims = result.claims

        # Create user session or JWT
        return jsonify({
            'success': True,
            'userId': claims['sub'],
            'email': claims.get('email')
        })
    except Exception as error:
        app.logger.error(f'Authentication failed: {error}')
        return jsonify({'error': 'Authentication failed'}), 401

Hawcx Delegation Client (MFA Setup)

For advanced use cases like setting up MFA for users programmatically:

from hawcx_oauth_client.delegation import HawcxDelegationClient, MfaMethod
import os

# Initialize the delegation client with your signing/encryption keys
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'),
    base_url=os.getenv('HAWCX_BASE_URL') or 'https://api.hawcx.com',
    sp_id=os.getenv('OAUTH_CLIENT_ID')
)

# Initiate MFA setup (Email, SMS, or TOTP)
result = client.initiate_mfa_change(
    userid='[email protected]',
    mfa_method=MfaMethod.SMS,
    phone_number='+15551234567'
)

# Verify OTP and complete MFA setup
client.verify_mfa_change(
    userid='[email protected]',
    session_id=result['session_id'],
    otp='123456'
)

# Get user credentials
creds = client.get_user_credentials('[email protected]')
print(f"MFA method: {creds.get('mfa_method')}")

Configuration

Environment Variables

For OAuth Code Exchange:

# Config ID (public identifier)
HAWCX_API_KEY="your-config-id"
# Optional base URL override
HAWCX_BASE_URL="https://api.hawcx.com"

For Hawcx Delegation:

SP_ED25519_PRIVATE_KEY_PEM="-----BEGIN PRIVATE KEY-----..."
SP_X25519_PRIVATE_KEY_PEM="-----BEGIN PRIVATE KEY-----..."
IDP_ED25519_PUBLIC_KEY_PEM="-----BEGIN PUBLIC KEY-----..."
IDP_X25519_PUBLIC_KEY_PEM="-----BEGIN PUBLIC KEY-----..."
OAUTH_CLIENT_ID="your-client-id"

Integration Examples

Flask

from flask import Flask, request, jsonify, session
from hawcx_oauth_client import HawcxOAuth
import os

app = Flask(__name__)
app.secret_key = os.getenv('FLASK_SECRET_KEY')

oauth = HawcxOAuth(config_id=os.getenv('HAWCX_API_KEY'))

@app.route('/exchange', methods=['POST'])
def exchange():
    data = request.json
    auth_code = data.get('authCode')
    code_verifier = data.get('codeVerifier')

    if not auth_code or not code_verifier:
        return jsonify({'error': 'Missing authCode or codeVerifier'}), 400

    try:
        result = oauth.exchange_code(auth_code, code_verifier)
        claims = result.claims
        session['user_id'] = claims['sub']
        session['email'] = claims.get('email')
        return jsonify({'success': True, 'userId': claims['sub']})
    except Exception as error:
        app.logger.error(f'Authentication failed: {error}')
        return jsonify({'error': 'Authentication failed'}), 401

Django

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from hawcx_oauth_client import HawcxOAuth
import os

oauth = HawcxOAuth(config_id=os.getenv('HAWCX_API_KEY'))

@require_http_methods(["POST"])
def exchange(request):
    auth_code = request.POST.get('authCode')
    code_verifier = request.POST.get('codeVerifier')

    if not auth_code or not code_verifier:
        return JsonResponse({'error': 'Missing authCode or codeVerifier'}, status=400)

    try:
        result = oauth.exchange_code(auth_code, code_verifier)
        claims = result.claims
        request.session['user_id'] = claims['sub']
        request.session['email'] = claims.get('email')
        return JsonResponse({'success': True, 'userId': claims['sub']})
    except Exception:
        return JsonResponse({'error': 'Authentication failed'}, status=401)

FastAPI

from fastapi import FastAPI
from fastapi.responses import JSONResponse
from hawcx_oauth_client import HawcxOAuth
import os

app = FastAPI()

oauth = HawcxOAuth(config_id=os.getenv('HAWCX_API_KEY'))

@app.post('/exchange')
async def exchange(payload: dict):
    auth_code = payload.get('authCode')
    code_verifier = payload.get('codeVerifier')

    if not auth_code or not code_verifier:
        return JSONResponse({'error': 'Missing authCode or codeVerifier'}, status_code=400)

    try:
        result = oauth.exchange_code(auth_code, code_verifier)
        claims = result.claims
        return JSONResponse({
            'success': True,
            'userId': claims['sub'],
            'email': claims.get('email')
        })
    except Exception:
        return JSONResponse({'error': 'Authentication failed'}, status_code=401)

PKCE Support

codeVerifier is required for the exchange. Store it on the client and send it alongside authCode when your backend calls exchange_code().

Next Steps

  • View the complete API reference for advanced features and detailed method signatures
  • Set up MFA management for your users
  • Join our developer community on Slack for support and updates