ID Token Verification

Verify Hawcx-issued ID Tokens with any OIDC-compatible JWT library

Hawcx issues OIDC Core 1.0 ID Tokens. After a user authenticates through the Hawcx SDK, your backend redeems the resulting authorization code for a signed ID Token at Hawcx's token endpoint, then verifies the token with any OIDC-compatible JWT library such as python-jose, jose for Node, nimbus-jose-jwt, or java-jwt.

The authentication flow itself is proprietary Hawcx, not OIDC. Only the issued token and the JWKS endpoint use OIDC-shaped pieces. This means your backend uses a JWT library, not a full OIDC client library that auto-discovers and handles browser redirects.

Page Summary

  • Hawcx mints standards-compliant signed JWTs (OIDC Core 1.0 §2 ID Tokens).
  • Verify them with any OIDC-compatible JWT library configured with your issuer URL and audience.
  • Public signing keys are published at a JWKS endpoint.
  • A discovery document is provided as a convenience for libraries that auto-fetch it; fetching the JWKS endpoint directly works equally well.
  • Each Hawcx environment has its own issuer string.

Issuer URLs

The issuer URL is the string your JWT library compares against the token's iss claim. Configure it as a constant in your backend.

EnvironmentIssuer URL
Productionhttps://api.hawcx.com
SandboxProvided in the Admin Console when your sandbox project is created

Hawcx is not a full OpenID Provider

Authentication happens through the Hawcx SDK, not via a browser redirect to an authorization endpoint. The discovery document deliberately omits authorization_endpoint, userinfo_endpoint, revocation_endpoint, response_types_supported, grant_types_supported, and code_challenge_methods_supported, since those describe a redirect flow Hawcx doesn't expose. Use a standard JWT library, not a full OIDC client. PKCE is still enforced at the token endpoint; only its discovery metadata is omitted.

Setting Up Token Verification

To verify Hawcx-issued tokens, you need:

  1. A Hawcx project provisioned in the Admin Console.
  2. Your project credential (X-Config-Id), issued at project creation and injected by the Hawcx API gateway when your backend calls the token endpoint.
  3. Your project's Client ID (called Client ID in the Admin Console; stamped into every ID Token as the aud claim). Auto-generated as a UUID at project creation; renameable any time, see Changing the audience value. Pin it in your backend as the audience argument to your JWT library.
  4. Your issuer URL, environment-specific and published in the Admin Console.

Once those values are in your backend configuration, point a JWT library at the JWKS endpoint and pass audience= and issuer= to its verify call.

Accessing the Service

The JWKS Endpoint

The JWKS endpoint is the only Hawcx endpoint your JWT library needs to fetch in order to verify tokens.

curl https://api.hawcx.com/.well-known/jwks.json

Returns a standard JSON Web Key Set. Match the kid from the ID Token's JWT header against keys[].kid to select the verification key.

See the JWKS endpoint reference for the response schema.

The Discovery Document (Optional)

Hawcx provides an OIDC discovery document for libraries that auto-fetch it. It is not required; verification works equally well by fetching the JWKS endpoint directly.

curl https://api.hawcx.com/.well-known/openid-configuration
{
  "issuer": "https://api.hawcx.com",
  "token_endpoint": "https://api.hawcx.com/oauth2/token",
  "jwks_uri": "https://api.hawcx.com/.well-known/jwks.json",
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["ES256"],
  "scopes_supported": ["openid", "profile", "email"],
  "token_endpoint_auth_methods_supported": ["none"],
  "claims_supported": [
    "iss", "sub", "aud", "iat", "nbf", "exp", "jti",
    "auth_time", "nonce", "amr", "acr",
    "email", "email_verified",
    "phone_number", "phone",
    "cnf"
  ]
}

The omitted fields (authorization_endpoint, userinfo_endpoint, revocation_endpoint, response_types_supported, grant_types_supported, code_challenge_methods_supported) describe a redirect flow Hawcx doesn't have. JWT libraries that consume jwks_uri, issuer, and id_token_signing_alg_values_supported work fine; full-flow OIDC clients will not.

See the Discovery document reference for the full field list.

Authenticating the User

The end-to-end flow has three stages:

  1. User authentication, performed by the Hawcx SDK using Hawcx's proprietary protocol, not by an OIDC redirect. On success, your backend receives an authorization code from the SDK.
  2. Code exchange, where your backend POSTs the code and PKCE verifier to the Hawcx token endpoint and receives a signed id_token.
  3. Token verification, where your backend verifies the ID Token's signature and claims using the public JWKS.

Stages 2 and 3 are standards-shaped: stage 2 resembles RFC 6749 §4.1.3 (with PKCE per RFC 7636), and stage 3 is plain JWT verification per OIDC Core 1.0 §2 + §3.1.3.7. Stage 1 is Hawcx-specific.

Exchange code for an ID Token

POST /oauth2/token HTTP/1.1
Host: api.hawcx.com
Content-Type: application/x-www-form-urlencoded
X-Config-Id: <your_project_credential>

code=<authorization_code>&code_verifier=<pkce_verifier>

Returns:

{
  "id_token": "eyJraWQiOi...",
  "token_type": "Bearer",
  "expires_in": 3600
}

The authorization code is single-use and short-lived. Redeem it immediately on receipt. See the token endpoint reference for full request/response/error semantics.

Validating an ID Token

Always pass audience and issuer to your JWT library

Most JWT libraries silently skip the aud and iss equality checks when the expected values aren't provided. Without them, your service would accept any Hawcx-signed token from any project, defeating the protection these claims exist to provide. This is the single most common integration mistake.

Every ID Token is a signed JWT. Validation steps (per OIDC Core §3.1.3.7):

  1. Decode the JWT and read the kid from the header.
  2. Fetch (and cache) the JWKS. Select the key whose kid matches.
  3. Verify the signature using the key's algorithm.
  4. Verify the iss claim equals your configured issuer URL.
  5. Verify the aud claim equals your project's audience.
  6. Verify the exp claim is in the future and iat / nbf are in the past.
  7. Verify nonce equals the value you supplied at auth time, if applicable.

Any compliant JWT library performs steps 1 through 6 automatically when you pass audience= and issuer=.

Example: Python

from jose import jwt
import httpx

ISSUER = "https://api.hawcx.com"
AUDIENCE = "your-project-audience"

# Fetch JWKS directly (no discovery needed)
jwks = httpx.get(f"{ISSUER}/.well-known/jwks.json").json()

claims = jwt.decode(
    id_token,
    jwks,
    algorithms=["ES256"],
    audience=AUDIENCE,
    issuer=ISSUER,
)

user_id = claims["sub"]

Example: Node.js

import * as jose from 'jose';

const ISSUER = 'https://api.hawcx.com';
const AUDIENCE = 'your-project-audience';

const jwks = jose.createRemoteJWKSet(
  new URL(`${ISSUER}/.well-known/jwks.json`)
);

const { payload } = await jose.jwtVerify(idToken, jwks, {
  issuer: ISSUER,
  audience: AUDIENCE,
});

const userId = payload.sub;

Obtaining User Information

Hawcx does not expose a UserInfo endpoint. Every claim about the user is minted directly into the ID Token. After verification, read the claims you need from the verified payload:

FieldClaimNotes
Stable user IDsubThe identity key linking your user records to Hawcx. Most apps store it as a unique-indexed column (e.g. users.hawcx_sub) and keep their own internal primary key.
EmailemailPresent when the user has a verified email on file.
Email verifiedemail_verifiedtrue whenever email is present. Hawcx only stores verified addresses.
Phonephone_numberOIDC Core §5.1 standard claim. The legacy phone claim is also emitted during the deprecation window.
Authentication timeauth_timeUnix epoch seconds for when the auth flow completed.
Methods usedamrRFC 8176 array describing the factors. See the table below.

See the ID Token reference for the complete claim list.

Advanced Topics

Caching the JWKS

Hawcx does not currently send Cache-Control headers on the JWKS endpoint. A reasonable default is to cache it for 5 to 10 minutes. On signature verification failure, force-refetch the JWKS before retrying. This handles the case where a key was rotated since your cache was populated.

Key Rotation Posture

Hawcx currently uses a single signing key per environment. If a key rotation occurs, you will be notified in advance, and the JWKS endpoint will publish the new key. Clients must re-fetch JWKS on kid lookup miss.

Hawcx-Specific Claims

In addition to standard OIDC claims, ID Tokens include the following extensions:

ClaimDescription
amrAuthentication Methods References per RFC 8176. Always includes "swk" (proof-of-possession of the device-bound software key). When MFA is performed, "mfa" is added along with the specific factor ("otp" for TOTP or email OTP, "sms" for SMS OTP).
acrAuthentication Context Class Reference. Always urn:hawcx:pwdless:v1, indicating Hawcx's device-bound, passwordless authentication.
cnfConfirmation claim for token binding. When present, contains jkt, the SHA-256 thumbprint of the JWK the token is bound to. See device-bound authentication.

Interpreting amr

The amr array tells your application which authentication factors were used. Possible shapes:

Token amrMeaning
["swk"]Device-bound authentication only, no MFA.
["swk", "mfa", "otp"]Device auth plus an OTP factor (TOTP or email OTP).
["swk", "mfa", "sms"]Device auth plus an SMS OTP factor.
["swk", "mfa"]Device auth plus a second device factor.

The legacy top-level mfa_method claim is no longer emitted. Read amr instead.

Changing the audience value

The aud claim's value is the project's Client ID in the Admin Console, auto-generated as a UUID v4 at project creation. Renameable any time.

To change it:

  1. Admin Console → your project → Settings → OAuth (or CMDB console Security section).
  2. Edit the Client ID field and save.
  3. Update your backend's audience constant and deploy.

Constraints:

  • ASCII alphanumeric plus ., _, -. Max 128 characters.
  • Globally unique across the environment. Duplicates return 409 CLIENT_ID_CONFLICT.

Rotating the Client ID is a coordinated change

Tokens issued before the rename carry the old aud and stay valid until they expire (default 3600s); tokens issued after carry the new aud. If your backend pins a single audience, either accept both values during an overlap window equal to your id_token TTL, or invalidate sessions on rotation and force re-authentication.

Multi-Environment Configuration

If your application runs against multiple Hawcx environments (production and sandbox, for instance), keep the issuer and audience values per-environment. Verifying a sandbox token against the production issuer fails by design: the token's iss claim won't match.

Next Steps