Python SDK API Reference

Complete API reference for the Hawcx Python SDK

Python SDK API Reference

HawcxOAuth

Initialize the OAuth client and exchange codes for verified claims.

from hawcx_oauth_client import HawcxOAuth
import os

oauth = HawcxOAuth(
    config_id=os.getenv('HAWCX_CONFIG_ID'),
    base_url=os.environ['HAWCX_BASE_URL'],  # from Admin Console
)

Discovery mode is recommended for new code

Prefer HawcxOAuth.from_issuer(...). It discovers the OAuth endpoints from the issuer and enforces iss + aud on every verify. The single-arg-style constructor above is legacy: it verifies the signature only and does not check iss or aud.

HawcxOAuth.from_issuer(issuer, config_id, client_id, *, timeout_seconds=..., discovery_timeout_seconds=..., clock_tolerance_seconds=...)

Discovers /.well-known/openid-configuration once at construction and enforces signature + iss + aud + exp + nbf on every exchange_code. Recommended for new integrations.

from hawcx_oauth_client import HawcxOAuth
import os

oauth = HawcxOAuth.from_issuer(
    os.environ['HAWCX_ISSUER'],
    os.environ['HAWCX_CONFIG_ID'],
    os.environ['HAWCX_CLIENT_ID'],  # expected `aud` on issued id_tokens
)
ParameterRequiredDescription
issuerYesYour environment's issuer URL; discovery resolves the token and JWKS endpoints from it.
config_idYesProject credential, sent as the X-Config-Id header on the token exchange.
client_idYesThe Admin Console value stamped as the aud claim on issued id_tokens; enforced on every verify.
timeout_secondsNoKeyword-only. HTTP timeout for the token exchange.
discovery_timeout_secondsNoKeyword-only. HTTP timeout for the one-time discovery fetch.
clock_tolerance_secondsNoKeyword-only. Leeway applied to exp / nbf / iat.

Raises DiscoveryError if the discovery document can't be resolved. An async equivalent (await HawcxOAuthAsync.from_issuer(...)) is also available.

exchange_code(auth_code, code_verifier)

Exchange an authorization code for verified claims.

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

# claims['sub'] = user ID
# claims.get('email') = verified email (if present)

Returns:

  • result.id_token: raw JWT (do not use as access token)
  • result.claims: verified claims

verify_token(token)

Verify a JWT and return its claims.

claims = oauth.verify_token(id_token)

Step-Up Client (Management API)

StepUpClient is the entry point for the management / step-up API (/v1/management/*) — start_token, consume_receipt, and a generic management_request escape hatch.

Recommended: reuse your OIDC signing key

with_private_key_jwt (Path A) is the recommended way to authenticate management API calls. It reuses the same Ed25519 private_key_jwt signing key you already registered for OIDC login — one key instead of the legacy four-key ECIES blob — and is fully standards-based (RFC 7523).

Prerequisite: enable jwt on the Management API Authentication card

Before management calls can authenticate with private_key_jwt, enable it for the project in the Admin Console → Project Settings → Management API Authentication:

  • Migrating — accepts both the legacy ECIES path and signed private_key_jwt. Use this during rollout so existing and new callers coexist.
  • Signed tokensprivate_key_jwt only (after every caller has migrated).

If the project is left on Legacy (ECIES only), private_key_jwt management calls are rejected with management_auth_mode_not_allowed (HTTP 401) — even with a correctly registered key. Note: regenerating an ECIES secret-key blob resets the project to Legacy, so set this after any blob regeneration.

Mints a short-lived per-request EdDSA Bearer JWT (iss = sub = client_id, aud = the full endpoint URL, ~60s lifetime, random jti, and a body_sha256 claim that binds the JWT to the exact request body bytes). Routing uses the X-Config-Id header.

import os
from hawcx_oauth_client import StepUpClient

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 registered in the Hawcx Admin Console
    client_id=os.environ["HAWCX_CLIENT_ID"],
    base_url="https://api.hawcx.com",
    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="[email protected]",
    purpose="change_mfa_method",
    new_mfa_method="email_otp",
)

# Finalize after the user completes the MFA challenge. The receipt is returned
# to your frontend by the Hawcx SDK once the challenge succeeds; forward it to
# your backend and pass it here.
receipt = "receipt-from-frontend-after-mfa"
client.consume_receipt(receipt=receipt)

# Generic call for any /v1/management/* endpoint
client.management_request(
    endpoint="/v1/management/users/mfa-enforcement",
    payload={"userid": "[email protected]"},
)

Responses carry an X-Response-Signature JWS — signed with the same key and algorithm the OIDC JWKS advertises (ES512 in production) — that you may verify against the OIDC JWKS you already trust.

StepUpClient.from_secret_key() (legacy, deprecated)

Legacy ECIES path — deprecated

from_secret_key and from_keys use the proprietary ECIES credential blob (hwx_sk_v1_…). They are deprecated but still functional (a DeprecationWarning is emitted) and will only be removed in a future major release. Migrate to with_private_key_jwt at your leisure.

from hawcx_oauth_client import StepUpClient

client = StepUpClient.from_secret_key(   # DeprecationWarning is emitted
    secret_key="hwx_sk_v1_...",
    base_url="https://api.hawcx.com",
    api_key="your-config-id",
    tenant_header_name="X-Config-Id",
    tenant_header_value="your-config-id",
)

client.start_token(user_id="[email protected]", purpose="change_mfa_method")

Delegation Client

Use the delegation client for backend-driven MFA setup and user/device management.

HawcxDelegationClient.from_keys()

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'),
    base_url=os.environ['HAWCX_BASE_URL'],
    sp_id=os.getenv('OAUTH_CLIENT_ID')
)

MFA

from hawcx_oauth_client.delegation import MfaMethod

result = client.initiate_mfa_change(
    userid='[email protected]',
    mfa_method=MfaMethod.SMS,
    phone_number='+15551234567'
)

client.verify_mfa_change(
    userid='[email protected]',
    session_id=result['session_id'],
    otp='123456'
)

Users

creds = client.get_user_credentials('[email protected]')