Skip to content

Expose session AMR / MFA-this-session signal in access JWT or webhook #655

@brett

Description

@brett

Use case

We're a B2B SaaS running AuthKit-managed SSO via workos-python 5.x. Our ISMS (SOC 2 / ISO 27001 controls) requires us to enforce MFA for the current session at the API request boundary — not "is the user MFA-enrolled". For a privileged action we need to answer "did this user MFA when this session was established?", and 403 if not.

What's missing

We can't answer that question with WorkOS today:

  • JWT templates explicitly cannot expose session.amr or MFA info (template surface is user / organization / organization_membership only).
  • Standard access JWT has no amr or acr claim. Confirmed in our dev environment — the JWT contains:
    client_id, email, email_verified, exp, iat, iss, jti, name,
    org_id, permissions, role, roles, sid, sub
    
  • load_sealed_session().authenticate() / authenticate_with_session_cookie decode the JWT internally but only surface named claims (sid, org_id, role, roles, permissions, entitlements, feature_flags). Anything else is dropped.
  • authentication.mfa_succeeded webhook has user_id, email, ip_address, user_agent but no session_id, so correlation with session.created is heuristic (user_id + close timestamp + IP/UA match). Not cryptographically tied to a session; insufficient for audit evidence.
  • list_authentication_factors answers enrollment, not session-MFA. A user with TOTP enrolled who logged in password-only would register as "MFA'd" under this signal.
  • AuthKit Actions are Allow/Deny only; can't mint custom JWT claims or attach session attributes.
  • Organization Authentication Policies can require MFA at the org level, but the policy is toggleable, doesn't appear in the token, and gives no per-request verification.

What we'd want (any one of these)

In priority order:

  1. amr claim in the access JWT (standard OIDC, e.g. ["mfa"] or ["pwd", "totp"]). Would let the API verify session-MFA without an extra round-trip. Cleanest answer.
  2. session_id on the authentication.mfa_succeeded webhook payload. Lets us build a (session_id → mfa_verified_at) table from webhook events and tie session establishment to MFA cryptographically. Less convenient than (1) but workable.
  3. Custom-claim minting in AuthKit Actions. Lets us write a one-line Action that copies AMR from session context to a JWT claim ourselves. Most flexible; works for adjacent use cases (custom roles, feature flags, etc.).

Why filing here

Not strictly an SDK issue — the underlying API change is what unblocks this. But since workos-python is the SDK we use, and the SDK's AuthenticateWithSessionCookieSuccessResponse would need to surface amr even if the API shipped it, recording the request here.

If there's a better place to route this (internal tracker, support ticket, public roadmap), happy to mirror.

Related

  • Cross-link: same ask filed on workos/authkit-nextjs for the consumer-side SDK helper. (will paste link after filing)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions