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-clientStep 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-idWhere 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_IDis required byfrom_issuer(the expectedaudon 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'}), 401Step 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 userOptional: 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