> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Step-Up Authentication

> Require users to re-verify their identity before sensitive actions using elevated access tokens. Includes re-auth (email, SMS, social/OAuth, wallet) and MFA (passkey, TOTP, recovery codes).

<Note>
  Step-up authentication is enforced when you set your minimum API version to `2026-04-01` in [Dashboard > Developers > API & SDK Keys](https://app.dynamic.xyz/dashboard/developer/api). Implement the required flows in your app before enabling enforcement. See the [API version upgrade guide](/overview/migrations/api/2026_04_01) for details.
</Note>

## Overview

Step-up authentication requires users to re-verify their identity before performing sensitive actions — exporting a private key, linking a new credential, deleting a passkey, etc. After successful verification, the user receives an **elevated access token**: a short-lived, scope-bound JWT that authorizes the specific operation.

Step-up authentication encompasses both re-authentication and MFA:

* **Re-authentication** — Email OTP, SMS OTP, OAuth (social), or external wallet signature. The user proves control of an existing credential. Embedded wallets cannot be used for step-up verification.
* **MFA (multi-factor authentication)** — Passkey, TOTP, or recovery code. The user proves possession of a registered second factor.

When MFA is enabled and the user has registered MFA methods, re-authentication methods are blocked for elevated token issuance — the user must verify through MFA instead.

<Note>
  For MFA-specific setup (enrollment, session-based MFA, device management), see [Multi-Factor Authentication (MFA)](/overview/authentication/mfa). If your users have MFA enabled, the SDK automatically routes step-up verification through MFA.
</Note>

<Warning>
  **Password-encrypted wallets** (WaaS wallets protected by a user-set password) are outside the scope of step-up authentication. Password decryption is handled by the wallet service independently.
</Warning>

## Enabling step-up authentication

Step-up authentication is enforced once you set your minimum API version to `2026_04_01` via the [Developers > API & SDK Keys](https://app.dynamic.xyz/dashboard/developer/api) page in your dashboard.

Until you set the minimum version, the backend will not require elevated access tokens on any endpoints — you can implement the step-up flows in your app first and enable enforcement when ready.

New environments have step-up authentication enforced by default. Only environments created before `2026_04_01` was introduced need to opt in.

<Info>
  After enabling, step-up is enforced server-side — even if a client sends requests without an elevated token, the backend will reject them with a `403`. Make sure your integration handles the step-up flow before enabling enforcement.
</Info>

## When is step-up authentication required?

When step-up authentication is enabled for your environment, the backend enforces it on sensitive operations. The user must present a valid elevated access token or the request is rejected with a `403`.

| Action                                                                          | Required scope      | Enforced           |
| ------------------------------------------------------------------------------- | ------------------- | ------------------ |
| Export a wallet private key                                                     | `wallet:export`     | Always             |
| Sign a message or transaction                                                   | `wallet:sign`       | Only if configured |
| Link a new credential <br />(wallet, email, phone, social, passkey, MFA device) | `credential:link`   | Always             |
| Unlink a credential <br />(wallet, email, phone, social, passkey, MFA device)   | `credential:unlink` | Always             |

Step-up is **not** required for:

* Initial sign-in and sign-up flows
* Reading user data or wallet balances
* Signing transactions with an embedded wallet (unless [`wallet:sign`](#scopes) is configured)

If you're using Dynamic's SDK widget (React SDK), these prompts are handled automatically — the widget detects when step-up is needed and shows the verification UI before proceeding. For headless SDKs (JavaScript, React Native), use the SDK methods documented in the implementation guides below.

## How it works

1. **Check** — Before a sensitive action, the SDK checks whether the user already has a valid elevated access token for the required scope.
2. **Verify** — If no valid token exists, the user is prompted to verify. The SDK automatically selects MFA or re-authentication based on the user's configuration.
3. **Use** — After successful verification, the token is stored in SDK state. The SDK automatically attaches it to the relevant API calls — no manual token handling is needed.

```mermaid theme={"system"}
sequenceDiagram
    participant App
    participant SDK
    participant Backend

    App->>SDK: checkStepUpAuth({ scope })
    SDK-->>App: { isRequired: true, credentials, defaultCredentialId }

    App->>SDK: promptStepUpAuth({ requestedScopes })
    note right of SDK: Auto-routes to MFA or re-auth
    SDK->>Backend: Verify identity + requestedScopes
    Backend-->>SDK: Elevated access token (scoped JWT)
    SDK->>SDK: Store token in client state

    App->>SDK: Perform sensitive operation
    note right of SDK: Token attached automatically
    SDK->>Backend: Operation + elevated token
    Backend-->>App: Success
```

## Supported verification methods

| Method               | Type    | Description                                                         |
| -------------------- | ------- | ------------------------------------------------------------------- |
| **Email OTP**        | Re-auth | One-time code sent to the user's verified email                     |
| **SMS OTP**          | Re-auth | One-time code sent to the user's verified phone number              |
| **Wallet signature** | Re-auth | Sign a message with a connected wallet                              |
| **Social (OAuth)**   | Re-auth | Re-authenticate with a linked social account (Google, GitHub, etc.) |
| **Passkey**          | MFA     | Authenticate with a registered passkey (WebAuthn)                   |
| **TOTP**             | MFA     | Enter a code from an authenticator app                              |
| **Recovery codes**   | MFA     | Use a backup recovery code                                          |

## Scopes

Elevated access tokens are bound to specific scopes. When requesting step-up authentication, specify which scopes you need via `requestedScopes`. The table below shows each scope, which SDK operations require it, and the underlying API endpoints that enforce it.

**Exclusive** scopes must be requested alone — they cannot be combined with other scopes in a single `requestedScopes` request. Non-exclusive scopes can be freely combined (e.g., `['credential:link', 'credential:unlink']`).

### Wallet operations

| Scope           | SDK operation                                         | API endpoint                                                                                                               | Single-use   | Exclusive |
| --------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------ | --------- |
| `wallet:export` | Export a wallet's private key or seed phrase          | [`POST .../waas/{walletId}/privateKey/export`](/api-reference/sdk/export-private-key-of-a-waas-account)                    | Yes          | Yes       |
| `wallet:sign`   | Sign a message or transaction with an embedded wallet | [`POST .../waas/{walletId}/delegatedAccess/signMessage`](/api-reference/waas/sign-a-message-with-a-delegated-waas-account) | Configurable | Yes       |

### Credential operations

| Scope               | SDK operation                 | API endpoint                                                                                     | Single-use | Exclusive |
| ------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------ | ---------- | --------- |
| `credential:link`   | Link a wallet                 | [`POST .../verify/link`](/api-reference/sdk/link-wallet-to-user)                                 | No         | No        |
|                     | Verify a wallet (linking)     | [`POST .../wallets/verify`](/api-reference/sdk/verify-payload-and-return-jwt)                    |            |           |
|                     | Link an OAuth social account  | [`POST .../providers/{providerType}/verify`](/api-reference/sdk/oauth-provider-verify-endpoint)  |            |           |
|                     | Verify email OTP (linking)    | [`POST .../emailVerifications/verify`](/api-reference/sdk/verify-email-verification-request)     |            |           |
|                     | Verify SMS OTP (linking)      | [`POST .../smsVerifications/verify`](/api-reference/sdk/verify-sms-verification-request)         |            |           |
|                     | Register a passkey MFA device | [`POST .../users/mfa/passkey`](/api-reference/sdk/register-a-new-passkey-mfa-device)             |            |           |
|                     | Register a TOTP MFA device    | [`POST .../users/mfa/totp`](/api-reference/sdk/verify-totp-mfa-device)                           |            |           |
| `credential:unlink` | Unlink a credential           | [`POST .../verify/unlink`](/api-reference/sdk/unlink-wallet-from-user)                           | No         | No        |
|                     | Delete a passkey              | [`DELETE .../users/passkeys`](/api-reference/sdk/delete-a-passkey)                               |            |           |
|                     | Delete an MFA device (TOTP)   | [`DELETE .../users/mfa/{mfaDeviceId}`](/api-reference/sdk/delete-a-device-if-not-default-device) |            |           |

<Info>
  **Single-use scopes** (like `wallet:export`) are consumed after the SDK uses them for the first qualifying API call. The user must re-verify to perform the action again.
</Info>

<Note>
  The `credential:link` scope is required on verification endpoints (email, SMS, OAuth, wallet) **only when the request includes `requestedScopes`** — meaning the caller is performing step-up reauthentication. Normal sign-in and sign-up flows through these same endpoints do not require an elevated token.
</Note>

## Token lifecycle

| Property               | Single-use tokens                                                                | Multi-use tokens                     |
| ---------------------- | -------------------------------------------------------------------------------- | ------------------------------------ |
| **Expiration**         | 5 minutes                                                                        | 10 minutes                           |
| **Consumed after use** | Yes — removed from state after the SDK uses it for the first qualifying API call | No — remains valid until expiration  |
| **Can combine scopes** | No — must be the only scope requested                                            | Yes — multiple scopes in one request |
| **Scope-bound**        | Yes                                                                              | Yes                                  |
| **Automatic cleanup**  | Expired tokens are filtered out automatically                                    | Same                                 |

## Dynamic's built-in UI

When using Dynamic's built-in UI (available in the React SDK), step-up authentication is handled automatically for Dynamic's own operations:

* **Wallet export** — The export flow prompts for step-up before showing the private key.
* **Credential linking/unlinking** — Linking a new wallet, social account, or email/phone prompts for step-up in the widget UI.
* **Passkey/TOTP deletion** — The MFA management views prompt for step-up before deletion.

No additional code is needed for these flows when step-up authentication is enabled in your [dashboard settings](https://app.dynamic.xyz/dashboard/security).

For **custom operations** or **headless implementations**, use the SDK methods documented in the guides below.

## Migration from MFA tokens

<Warning>
  The `createMfaToken` parameter on MFA verification methods is deprecated. Use `requestedScopes` instead. See [migration guide](/overview/migrations/api/2026_04_01-mfa-migration).
</Warning>

|                     | `createMfaToken` (deprecated)    | `requestedScopes` (recommended)         |
| ------------------- | -------------------------------- | --------------------------------------- |
| **Token type**      | Unscoped MFA token               | Scoped elevated access token (JWT)      |
| **Expiration**      | Single-use, no time limit        | Time-limited (5 or 10 min)              |
| **Scope**           | None — accepted for any action   | Bound to specific scopes                |
| **Storage**         | Manual handling required         | Automatically stored and applied by SDK |
| **MFA enforcement** | Not enforced for non-MFA methods | Enforced when MFA is enabled            |

For a complete migration walkthrough with before/after code examples, see the [action-based MFA to step-up migration guide](/overview/migrations/api/2026_04_01#migrating-from-action-based-mfa-to-step-up-authentication).

## SDK implementation guides

<CardGroup cols={2}>
  <Card title="JavaScript SDK" icon="js" href="/javascript/authentication-methods/step-up-auth/overview">
    Headless implementation with direct function calls. Use this for vanilla JS, Vue, Svelte, Angular, or any non-React framework.
  </Card>

  <Card title="React SDK" icon="react" href="/react/authentication-methods/step-up-auth/overview">
    Hooks with automatic routing, Dynamic UI prompts, and headless React patterns.
  </Card>

  <Card title="React Native SDK" icon="react" href="/react-native/authentication-methods/step-up-auth/overview">
    Built-in UI prompts and headless verification for React Native mobile apps.
  </Card>

  <Card title="Flutter SDK" icon="flutter" href="/flutter/authentication-methods/step-up-auth/overview">
    Step-up auth module with built-in UI prompts and individual verification methods.
  </Card>

  <Card title="Swift SDK" icon="swift" href="/swift/step-up-auth">
    Step-up auth module with built-in UI prompts and individual verification methods for iOS.
  </Card>

  <Card title="Kotlin SDK" icon="android" href="/kotlin/step-up-auth">
    Step-up auth module with built-in UI prompts and individual verification methods for Android.
  </Card>
</CardGroup>
