Integrate in Existing Python Project

Add Hawcx authentication to an existing Python application

This guide walks through adding Hawcx OAuth authentication to an existing Python backend.

Step 1: Install the SDK

pip install hawcx-oauth-client

Step 2: Set Up Environment Variables

Create a .env file or configure your environment with:

# All three from Admin Console → Project Settings (environment-specific)
HAWCX_BASE_URL="<Base URL from Admin Console>"   # issuer URL for discovery
HAWCX_CONFIG_ID="<Config ID from Admin Console>"
HAWCX_CLIENT_ID="<Client ID from Admin Console>"

# Optional (for MFA management via StepUpClient + private_key_jwt)
HAWCX_OIDC_PRIVATE_KEY_PEM=-----BEGIN PRIVATE KEY-----...
HAWCX_PRIVATE_KEY_KID=your-key-id

Where to find these values: Open the Hawcx Admin Console, go to Project Settings, and copy the Base URL, Config ID, and Client ID. All three are environment-specific — the base URL has no universal default. HAWCX_CLIENT_ID is required by from_issuer (the expected aud on issued id_tokens).

Step 3: Create an Exchange Endpoint

Create a new route to handle Hawcx code exchange:

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

auth_bp = Blueprint('auth', __name__)

oauth = HawcxOAuth.from_issuer(
    os.environ['HAWCX_BASE_URL'],   # issuer URL (Base URL from Admin Console)
    os.environ['HAWCX_CONFIG_ID'],
    os.environ['HAWCX_CLIENT_ID'],  # expected `aud` on issued id_tokens
)

@auth_bp.route('/exchange', methods=['POST'])
def exchange():
    try:
        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

        result = oauth.exchange_code(auth_code, code_verifier)
        claims = result.claims

        # Find or create user in your database
        user = find_or_create_user({
            'id': claims['sub'],
            'email': claims.get('email')
        })

        # Create your application's session/JWT
        session_token = generate_session_token(user)

        return jsonify({
            'success': True,
            'sessionToken': session_token,
            'user': {
                'id': user.id,
                'email': user.email
            }
        })
    except Exception as error:
        print(f'Hawcx exchange error: {error}')
        return jsonify({'error': 'Authentication failed'}), 401

Step 4: Integrate with Your User Management

Update your user service to handle Hawcx identities:

# services/user_service.py
from db import session
from models import User

class HawcxUser:
    def __init__(self, id: str, email: str | None):
        self.id = id
        self.email = email

def find_or_create_user(hawcx_user: HawcxUser):
    user = session.query(User).filter_by(hawcx_id=hawcx_user.id).first()

    if not user:
        user = User(hawcx_id=hawcx_user.id, email=hawcx_user.email)
        session.add(user)
        session.commit()

    return user

Optional: Backend-Driven MFA Management

If you need to manage MFA from your backend, use StepUpClient (the management / step-up API):

import os
from hawcx_oauth_client import StepUpClient

# Reuses the same Ed25519 key you registered for OIDC login (one key, RFC 7523)
client = StepUpClient.with_private_key_jwt(
    oidc_signing_key=os.environ['HAWCX_OIDC_PRIVATE_KEY_PEM'],  # Ed25519 PEM or bytes
    kid=os.environ['HAWCX_PRIVATE_KEY_KID'],                    # key id from Admin Console
    client_id=os.environ['HAWCX_CLIENT_ID'],
    base_url=os.environ['HAWCX_BASE_URL'],
    config_id=os.environ['HAWCX_CONFIG_ID'],
)

# Begin a step-up flow (purposes: "change_mfa_method", "change_phone_number")
result = client.start_token(
    user_id='user@example.com',
    purpose='change_mfa_method',
    new_mfa_method='sms_otp',   # one of: "sms_otp", "email_otp", "totp"
)

# Finalize once the user completes the MFA challenge (receipt comes from your frontend)
client.consume_receipt(receipt='receipt-from-frontend-after-mfa')

See the Step-Up Client (Management API) reference for management_request and full method details.

Last updated on