POST /v1/session/stepup/request, Prelude calls your step-up hook — the signal_hook_url you registered in the step-up configuration. Your hook decides whether to grant the scope immediately, require a multi-step challenge, or block the request.
Hook request
Prelude sends a signedPOST request to your hook URL with the following JSON body:
Request fields
| Field | Type | Description |
|---|---|---|
scope_requested | string | The scope the user is requesting. |
user_id | string | The Prelude user ID. |
identifiers | array | The user’s identifiers (email addresses, phone numbers). |
identifiers[].type | string | "email_address" or "phone_number". |
identifiers[].value | string | The identifier value. |
signals | object | Contextual signals from the user’s session. |
signals.user_agent | string | The user’s browser or app user agent string. |
signals.platform | string | The platform (e.g. "WEB", "ANDROID", "IOS"). |
signals.ip | string | The user’s IP address. |
metadata | object | Optional metadata passed by the frontend when requesting the scope. Max 5 fields, keys max 12 characters, values max 32 characters. |
Request headers
| Header | Description |
|---|---|
Content-Type | application/json |
User-Agent | Prelude-SessionStepUpHook/1.0 |
X-Webhook-Signature | Base64 URL-encoded RSASSA-PSS SHA-256 signature of the request body. |
X-Webhook-Signature-Key-Id | The ID of the signing key used to produce the signature. |
Request signature
The hook request is signed using the same mechanism as webhooks. Verify theX-Webhook-Signature header using the public key matching the X-Webhook-Signature-Key-Id from your application’s JWKS endpoint.
Hook response
Your endpoint must return a JSON response with a verdict.Grant immediately
Returnstatus: "continue" to grant the scope without any challenge:
Require a challenge
Returnstatus: "review" with one or more steps the user must complete:
Block the request
Returnstatus: "block" to deny the scope entirely:
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | "continue", "review", or "block". |
granted_for | integer | Yes (when continue or review) | Duration in seconds for which the scope is granted. Must be between 0 and 86400 (24 hours). |
grant_mode | string | Yes (when continue or review) | "single-use" or "session-bound". See below. |
steps | array | Yes (when review) | The steps the user must complete, in order. Must not be empty when status is review. Must not be present when status is continue or block. |
steps[].order | integer | Yes | The position of this step in the sequence (starting from 1). |
steps[].key | string | Yes | The step identifier. Use "verify_sms" or "verify_email" for Prelude-owned steps, or a custom key you registered in the step-up configuration. |
steps[].expiration_duration | integer | Yes | Time in seconds the user has to complete this step. Must be between 0 and 86400 (24 hours). |
Grant modes
| Mode | Behavior |
|---|---|
single-use | The scope is attached only to the next access token. It is not persisted on the session. granted_for must be at least 1 second. |
session-bound | The scope is stored on the session and included in every subsequent refresh for granted_for seconds. If granted_for is less than 1, it defaults to 600 seconds (10 minutes). |
Response constraints
| Rule | Limit |
|---|---|
| Maximum response body size | 64 KB |
granted_for range | 0 to 86400 seconds (24 hours). Cannot be negative. |
steps with review | Must contain at least one step. |
steps with continue or block | Must not be present. |
Step key format | Only a-z, A-Z, 0-9, and .-_: characters. |
Step expiration_duration range | 0 to 86400 seconds (24 hours). Cannot be negative. |
Response HTTP status
Your hook must return HTTP 200 with the JSON body. Any non-200 response or timeout (5 seconds) will cause the step-up request to fail.Example implementation
Here is a minimal Node.js example of a step-up hook:Custom steps and verification tokens
If your hook returns custom step keys (anything other thanverify_sms or verify_email), your backend must issue verification tokens to advance the challenge. See Custom Steps for the full verification token format, requirements, and code examples.