Step-up is when the platform demands MFA in the middle of a session. Even though the user signed in already (with or without MFA), specific events or conditions trigger a fresh challenge. The user completes MFA again; the session's AAL is bumped; the action proceeds.
Step-up is the dial between "MFA every sign-in" (annoying for users) and "MFA never" (insufficient for sensitive actions). It targets specifically the moments that matter.
Configure step-up policies
MFA → Adaptive step-up.
You define policies. Each policy has:
Trigger — what condition / event fires the step-up.
Required factor — which factor satisfies (any enrolled / specifically WebAuthn / specifically not SMS).
AAL target — what AAL the session should reach after the step-up completes.
Duration — how long the elevated AAL persists before re-prompting.
The policies stack — multiple triggers can each fire step-up; the most-restrictive applicable AAL wins.
Event-based triggers
Specific user actions that demand step-up:
Sensitive operations — changing primary email, deleting account, generating an API key. Configure per operation; the user-facing app or your code triggers the AAL check.
Admin tenant actions — performing high-risk admin operations (deleting an application, force-resetting another user's MFA, exporting users). Defaults to step-up for these.
First time accessing a resource class — first time the user opens "Payments" in the app, step up. Subsequent opens within the duration don't re-prompt.
Risk-based triggers
The platform's risk engine scores every sign-in attempt. Configure thresholds:
Risk score ≥ X → demand step-up before letting the session proceed.
From a new device → step-up on first sign-in from each new device fingerprint.
From a new country → step-up when the user signs in from a country they haven't signed in from in the last N days.
Geographic velocity — sign-in from one city, then sign-in from another city 5 minutes later (impossible travel) → step-up.
Threat intel hit — the user's IP appeared in a threat feed → step-up.
The risk engine is on by default; configure scoring + thresholds in Threat intelligence.
Duration
After step-up succeeds, the elevated AAL persists for the configured duration. Common values:
15 minutes — for AAL 2 in routine sensitive operations.
5 minutes — for AAL 3 in highly sensitive operations.
Tighter = more friction for power users doing many sensitive actions in a row. Looser = a stolen access token has a longer effectiveness window. The 15-minute default is a sensible balance.
The user experience
A user opens the "Change email" page in your app. Your app calls the API. The API returns 401 step_up_required with required_acr: aal2. The SDK reads this, shows the user a "Confirm your identity" prompt with their already-enrolled factor (passkey, TOTP, etc.). User confirms. SDK gets a fresh access token with the elevated AAL. Original API call retries; succeeds.
From the user's perspective, one extra "Confirm with Touch ID" tap inserted into the flow. The whole round trip is sub-2-seconds for WebAuthn; longer for TOTP or SMS.
The developer experience
Your applications need to honour the step-up contract:
Backend: check the access token's
acrclaim on sensitive endpoints. If insufficient, return 401 with the step_up_required envelope.Frontend: catch 401s with that envelope and call the SDK's
stepUpmethod.
See Step-up authentication (developer reference) for the full integration.
Per-tenant + per-application policies
Step-up policies live primarily at the tenant level. Individual applications can override:
"Tenant default: step-up on sensitive operations after 15 min."
"Application X: step-up on EVERY sensitive operation, no AAL caching."
Override in the application's authentication policy tab.
What to tell users
Step-up prompts have a friction cost. The right copy makes them feel protective rather than annoying:
"Confirm your identity before changing your email."
"You're signing into Finance from a new device — let's verify."
"We need to re-verify for this sensitive action."
Avoid "for security reasons" — too vague. Specific framing of WHY the prompt is appearing makes users tolerate it (and trust the platform more).
Configure factor downgrade
Some teams want "step-up via SMS is enough for low-sensitivity operations; only WebAuthn for high-sensitivity." Configure per-policy:
"Sensitive ops" policy → required factor: any enrolled. AAL 2.
"Highly sensitive ops" policy → required factor: WebAuthn or TOTP only (no SMS). AAL 3.
The user's existing factors determine which AAL is reachable. A user with only SMS can satisfy AAL 2 (SMS-enrolled session is AAL 2) but not AAL 3 (SMS doesn't satisfy AAL 3 by policy). The platform refuses the action; your application's frontend shows "this operation requires a stronger factor. Set up WebAuthn or TOTP to proceed."
Audit
Every step-up records:
auth.step_up_initiated— the platform triggered.auth.step_up_completed— succeeded.auth.step_up_failed— user dismissed or failed.auth.step_up_skipped— the policy didn't fire because the session already had sufficient AAL.
Filter audit on these to investigate "did step-up actually fire when it should have?" patterns.
Don't over-step-up
Step-up has a real cost. Reserve it for things that matter:
Changing email or phone.
Generating an API key.
Payouts above a threshold.
Modifying MFA factors.
Admin operations on other users.
Don't step-up:
Routine reads.
Preference changes.
Anything the user can undo themselves.
Over-stepping trains users to dismiss prompts reflexively, which weakens the prompt's signal when you really need it.