What you’ll build
Step-up authentication gates a sensitive action behind fresh authentication, scoped to aTokenScope such as wallet:sign or wallet:export. You’ll:
- Check whether the action’s scope currently needs step-up.
- Re-authenticate the user, passing that scope as
requestedScopes. This mints a short-lived elevated access token for the scope. - Perform the action — the SDK finds and consumes the matching elevated token automatically.
requestedScopes on the verify/authenticate call. This page uses email OTP for the full walkthrough, then shows the one-line change for every other method. If your backend authorizes the action instead of the user, an externally-issued JWT elevates the session server-side.
This is not the same as MFA. MFA (see MFA enrollment & management) is one credential type a user can present. Step-up is the scope-based elevation flow — your project settings decide whether a given scope requires it, and any credential the user has can satisfy it.
Prerequisites
- The user is already signed in. Step-up elevates an existing session; it is not a sign-in flow.
Checking whether step-up is required
This page gates signing as the running example, so every call below checks thewallet:sign scope. Swap it for whichever scope matches the action you’re protecting — the flow is identical.
checkStepUpAuth({ scope }) returns { isRequired, credentials, defaultCredentialId }. It resolves to isRequired: false immediately when a valid elevated token for the scope already exists; otherwise it asks the backend, which factors in your project settings. credentials lists the methods this user can use to satisfy the challenge, and defaultCredentialId is the one to pre-select in your UI (the sign-in credential, or the default / most-recently-added MFA device) — use it instead of blindly taking the first credential.
- TypeScript
- React
Full example: elevate with email OTP
Check the scope, re-authenticate only when needed, then perform the action. The sign call needs no elevated token passed to it — it reads the one thatverifyOTP just minted.
- TypeScript
- React
Use any auth method
Every credential type takes the samerequestedScopes argument. Swap the re-authentication step above for whichever the user has — the check-then-act structure stays identical. Each snippet below is just that one call.
- TypeScript
- React
Server-authorized step-up (external JWT)
The methods above elevate the session from something the user does in the browser. When your backend is the one authorizing the action — for example a server-side approval workflow, or trust already established by your own system — you elevate with an assertion JWT instead. Here the scope is not passed asrequestedScopes; it travels inside the signed JWT, so the browser can’t widen it.
How it works:
- Your backend mints a short-lived JWT and signs it with the key registered at your environment’s external auth JWKS URL. The JWT carries these claims:
sub— the user the elevation is for.scope— theTokenScopebeing granted (e.g.wallet:sign). This is what determines the elevated scope.jti— a unique id so the assertion can only be redeemed once.exp— a short expiry.
- Hand that JWT to the SDK. It verifies the signature against your JWKS, then mints and stores the elevated access token for the
scopeclaim. - Perform the action — the SDK consumes the matching elevated token exactly as with the user-driven methods.
- TypeScript
- React
Because the scope is baked into the signed assertion, you don’t call
checkStepUpAuth first for this path — your backend has already decided the elevation is warranted.Available scopes
Request the scope that matches the action you’re gating. Common SDK scopes:Handling errors
Step-up adds no error types of its own. Because any credential can satisfy the challenge, the errors you handle are the ones the re-authentication method you chose already throws — a wrong code, a rate-limited attempt, a rejected wallet signature — handled exactly as they are outside step-up. For example, the MFA methods (authenticateTotpMfaDevice, authenticatePasskeyMFA, authenticateMfaRecoveryCode) throw MfaInvalidOtpError on a wrong or expired code and MfaRateLimitedError after too many attempts; ask the user to re-enter or wait, and don’t run the action.
Two situations are specific to step-up itself:
checkStepUpAuth defaults to isRequired: true if the check itself fails, so a network error never silently skips the challenge. Gate the action on the check result, not on the UI.See also
- MFA enrollment & management — enroll the authenticator/passkey credentials a challenge can use
- Transaction confirmation & simulation — the
wallet:signaction you can gate - Wallet backup & recovery — the
wallet:exportaction you can gate