Skip to main content
Step-up authentication lets you require additional proof from an already-authenticated user before granting access to sensitive operations. Instead of re-authenticating from scratch, the user completes a challenge (SMS OTP, email OTP, etc.) and receives a time-limited scope on their session.

Prerequisites

  • A Prelude account with access to the Session API
  • An Application ID (appID) — see Applications
  • Your Management API key for backend calls
  • A working login flow (users must be authenticated before requesting step-up)

How it works

When a user requests a sensitive action, your frontend asks Prelude for a scope grant. Prelude calls a hook on your backend, where you decide whether to grant the scope immediately, require a challenge, or block the request entirely. If you require a challenge, Prelude walks the user through each step you defined. Prelude natively handles managed steps like verify_sms and verify_email — no extra work on your side. Once every step is completed, the scope is granted to the user’s access token.
You can also define custom steps handled by your own backend (e.g. KYC review, biometric check). See Custom Steps for details.

Configure step-up

1

Create a step-up configuration

Register your hook URL and allowed scopes.
curl -X POST https://api.prelude.dev/v2/session/apps/${APP_ID}/config/stepup \
  -H "Authorization: Bearer ${MANAGEMENT_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "signal_hook_url": "https://api.example.com/hooks/stepup",
    "jwks_url": "https://api.example.com/.well-known/jwks.json",
    "step_keys": [],
    "allowed_scopes": ["transfer:write", "payment:confirm"]
  }'
FieldRequiredDescription
signal_hook_urlYesThe URL Prelude calls when a scope grant is requested. See Step-Up Hook.
jwks_urlYesYour JWKS endpoint. Only required if you use custom steps.
step_keysYesCustom step keys for client-owned steps. Leave empty if you only use managed steps.
allowed_scopesYesThe scopes that can be requested via step-up.
Scope names must only contain: lowercase letters, uppercase letters, numbers, and the characters .-_:.
2

Implement the hook endpoint

Your backend must expose the hook URL you registered. When Prelude receives a step-up request, it calls your hook with user and session context. Your hook decides whether to grant, challenge, or block.See the full Step-Up Hook Reference for the request/response format and constraints.

The step-up flow

1. Request a scope grant

The frontend SDK initiates the flow by calling requestStepUp with a scope. Prelude calls your hook and returns one of:
StatusMeaning
continueScope granted immediately, no challenge needed. The SDK refreshes the session automatically.
reviewA challenge was created. The user must complete all steps.
blockScope denied.

2. Complete managed steps

Prelude handles the following step types natively:
Step keyDescription
verify_smsSMS OTP verification sent to the user’s phone number.
verify_emailEmail OTP verification sent to the user’s email address.
The SDK provides otpCreate, otpCheck, and otpRetry methods to drive these steps using the challengeId from the onChallenge callback.

3. Automatic completion

When the last step is completed, the SDK automatically refreshes the session with the granted scope. The new access token behavior depends on the grant_mode set by your hook:
Grant modeBehavior
single-useThe scope is attached only to this access token and expires after granted_for seconds. It is not persisted on the session.
session-boundThe scope is stored on the session and included in every subsequent refresh for granted_for seconds.
See the Web SDK Step-Up guide for the full integration with code examples.

Constraints and validation

Field format

All external fields (scopes, step keys, metadata keys) must match:
a-z A-Z 0-9 . - _ :
No other characters are allowed.

Metadata

RuleLimit
Maximum number of fields5
Maximum key length12 characters
Maximum value length32 characters

Hook response

RuleLimit
Maximum response size64 KB
granted_forIn seconds. Must be between 0 and 86400 (24 hours). Cannot be negative.
granted_for defaultWhen grant_mode is session-bound and granted_for < 1, it defaults to 600 seconds (10 minutes). When grant_mode is single-use, granted_for must be at least 1.
Hook timeout5 seconds. Your endpoint must respond within this time.
Step expiration_durationIn seconds. Must be between 0 and 86400 (24 hours). Cannot be negative.

Step-Up JWKS

Prelude exposes a dedicated JWKS endpoint for step-up token verification at:
https://<app_id>.session.prelude.dev/.well-known/step-up-jwks.json
This is separate from the main JWKS endpoint used for access token verification.

Security recommendations

Anti-replay: When your backend receives a request carrying a scope granted via step-up, you should allow each scoped token to be used only once. Track the token’s jti claim and reject any replayed token. This prevents an attacker from reusing a captured token to repeat a sensitive action.
  • Limit scope lifetime: Use the granted_for field to keep scoped access as short-lived as practical. A transfer confirmation might only need 60 seconds.
  • Use grant_mode: "single-use" for high-sensitivity operations (e.g. fund transfers). This ensures the scope is attached to a single access token and not persisted on the session.
  • Validate signals in your hook: Prelude sends user_agent, platform, and ip in the hook request. Use these to detect suspicious context changes (e.g. a different IP than the original login).

What’s next?

Custom Steps

Add client-owned steps like KYC review or biometric checks to your challenges.

Step-Up Hook

Full API reference for the hook endpoint your backend must implement.