Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
This guide is only relevant if you previously used action-based MFA to protect sensitive wallet operations. If you didn’t, you can skip it.
If you previously used action-based MFA to protect sensitive wallet operations, step-up authentication replaces and extends that functionality. The core concept is the same — require users to re-verify before sensitive actions — but step-up auth adds scoped elevated access tokens, re-authentication methods for non-MFA users, and automatic token handling by the SDK.
What changed
| Action-based MFA (before) | Step-up authentication (after) |
|---|
| Hook | useMfa / useAuthenticatePasskeyMFA | useStepUpAuthentication |
| Token type | Unscoped MFA token (createMfaToken) | Scoped elevated access token (requestedScopes) |
| Token handling | SDK-managed MFA token | SDK-managed elevated access token (scoped JWT) |
| Who can verify | Only users with MFA methods (TOTP/Passkey) | All users — MFA methods, email OTP, SMS OTP, wallet signature, or social OAuth |
| Scope | None — token accepted for any action | Bound to specific scopes (wallet:export, wallet:sign, credential:link, credential:unlink) |
| Expiration | Single-use, no time limit | Time-limited (5 min single-use, 10 min multi-use) |
Dashboard changes
No dashboard changes are required — your existing action-based MFA event
configuration (WaaS Export, WaaS Refresh, WaaS Sign, WaaS Reshare) carries over.
Make sure your code is fully updated before accepting the minimum API version at Dashboard > Developers > API & SDK Keys. Once set to 2026_04_01, the backend enforces step-up authentication immediately.
AI-assisted upgrade prompts
These prompts are designed for AI coding agents (Cursor, Claude Code, Copilot). Always review generated code before committing — agents can misread your project structure.For best results, install the Dynamic MCP in your agent so it can reference live documentation automatically. If you don’t have it installed, the prompts fall back to https://www.dynamic.xyz/docs/llms.txt.
Copy the prompt for your SDK and run it in your agent.
React
JavaScript
React Native
Flutter
Kotlin
Swift
I'm migrating my Dynamic SDK headless integration from action-based MFA to step-up authentication as part of the 2026_04_01 API upgrade.
If you have the Dynamic MCP installed, use it to reference the latest API.
Otherwise reference: https://www.dynamic.xyz/docs/llms.txt
In my codebase:
1. Find all usages of `useMfa`, `useAuthenticatePasskeyMFA`, and `usePromptMfaAuth`
2. Replace them with `useStepUpAuthentication` from `@dynamic-labs/sdk-react-core`
3. Replace all `createMfaToken` options with `requestedScopes` using the
appropriate `TokenScope` from `@dynamic-labs/sdk-api-core`
4. Replace all `useIsMfaRequiredForAction` calls with `isStepUpRequired`
5. Do not modify any files outside of the auth flow
After making changes, summarize what was updated and flag anything that
needs manual review.
I'm migrating my Dynamic SDK headless integration from action-based MFA
to step-up authentication as part of the 2026_04_01 API upgrade.
If you have the Dynamic MCP installed, use it to reference the latest API.
Otherwise reference: https://www.dynamic.xyz/docs/llms.txt
In my codebase:
1. Find all usages of `isMfaRequiredForAction` from `@dynamic-labs-sdk/client`
2. Replace them with `checkStepUpAuth`
3. Replace all `createMfaToken` and `createMfaTokenOptions` with `requestedScopes`
using the appropriate `TokenScope` from `@dynamic-labs/sdk-api-core`
on both `authenticateTotpMfaDevice` and `authenticatePasskeyMFA`
4. Do not modify any files outside of the auth flow
After making changes, summarize what was updated and flag anything that
needs manual review.
I'm migrating my Dynamic SDK headless integration from action-based MFA
to step-up authentication as part of the 2026_04_01 API upgrade.
If you have the Dynamic MCP installed, use it to reference the latest API.
Otherwise reference: https://www.dynamic.xyz/docs/llms.txt
In my codebase:
1. Find all usages of `client.mfa.isRequiredForAction` and replace with
`client.stepUpAuth.isStepUpRequired`
2. Find all usages of `client.mfa.authenticateDevice` and replace with
`client.stepUpAuth.verifyTotpMfa`
3. Find all usages of `client.passkeys.authenticateMFA` and replace with
`client.stepUpAuth.verifyPasskeyMfa`
4. Find all usages of `client.ui.mfa.show` and replace with
`client.stepUpAuth.promptStepUpAuth`
5. Replace all `createMfaToken` options with `requestedScopes` using
the appropriate `TokenScope`
6. Do not modify any files outside of the auth flow
After making changes, summarize what was updated and flag anything that
needs manual review.
I'm migrating my Dynamic SDK headless integration from action-based MFA
to step-up authentication as part of the 2026_04_01 API upgrade.
If you have the Dynamic MCP installed, use it to reference the latest API.
Otherwise reference: https://www.dynamic.xyz/docs/llms.txt
In my codebase:
1. Find all usages of DynamicSDK.instance.mfa related to action-based MFA checks
2. Replace them with DynamicSDK.instance.stepUpAuth.isStepUpRequired
3. Replace verification calls with the appropriate method:
- TOTP: DynamicSDK.instance.stepUpAuth.verifyTotpMfa
- Passkey: DynamicSDK.instance.stepUpAuth.verifyPasskeyMfa
- Prompt: DynamicSDK.instance.stepUpAuth.promptStepUpAuth
4. Replace all scope arguments with the string equivalents:
'wallet:export', 'wallet:sign', 'credential:link', 'credential:unlink'
5. Do not modify any files outside of the auth flow
After making changes, summarize what was updated and flag anything that
needs manual review.
I'm migrating my Dynamic SDK headless integration from action-based MFA
to step-up authentication as part of the 2026_04_01 API upgrade.
If you have the Dynamic MCP installed, use it to reference the latest API.
Otherwise reference: https://www.dynamic.xyz/docs/llms.txt
In my codebase:
1. Find all usages of action-based MFA checks in my Kotlin integration
2. Replace them with sdk.stepUpAuth.isStepUpRequired(scope)
3. Replace verification calls with the appropriate method:
- TOTP: sdk.stepUpAuth.verifyTotpMfa(code, deviceId, requestedScopes)
- Passkey: sdk.stepUpAuth.verifyPasskeyMfa(requestedScopes)
- OTP: sdk.stepUpAuth.verifyOtp(verificationToken, requestedScopes)
- Or let the SDK decide: sdk.stepUpAuth.promptStepUpAuth(requestedScopes)
4. Replace all scope arguments with the appropriate string equivalents:
'wallet:export', 'wallet:sign', 'credential:link', 'credential:unlink'
5. Do not modify any files outside of the auth flow
After making changes, summarize what was updated and flag anything that
needs manual review.
I'm migrating my Dynamic SDK headless integration from action-based MFA
to step-up authentication as part of the 2026_04_01 API upgrade.
If you have the Dynamic MCP installed, use it to reference the latest API.
Otherwise reference: https://www.dynamic.xyz/docs/llms.txt
In my codebase:
1. Find all usages of action-based MFA checks in my Swift integration
2. Replace them with sdk.stepUpAuth.isStepUpRequired(scope:)
3. Replace verification calls with the appropriate method:
- TOTP: sdk.stepUpAuth.verifyTotpMfa(code:deviceId:requestedScopes:)
- Passkey: sdk.stepUpAuth.verifyPasskeyMfa(requestedScopes:)
- OTP: sdk.stepUpAuth.verifyOtp(verificationToken:requestedScopes:)
- Or let the SDK decide: sdk.stepUpAuth.promptStepUpAuth(requestedScopes:)
4. Replace all scope arguments with the appropriate string equivalents:
'wallet:export', 'wallet:sign', 'credential:link', 'credential:unlink'
5. Do not modify any files outside of the auth flow
After making changes, summarize what was updated and flag anything that
needs manual review.
Code migration: before and after
Using Dynamic’s built-in UI
React
React Native
Flutter (no built-in UI)
Before — usePromptMfaAuth with createMfaToken: import { usePromptMfaAuth, useIsMfaRequiredForAction } from "@dynamic-labs/sdk-react-core";
import { MFAAction } from '@dynamic-labs/sdk-api-core';
const isMfaRequiredForAction = useIsMfaRequiredForAction();
const promptMfaAuth = usePromptMfaAuth();
const isMfaRequired = await isMfaRequiredForAction({
mfaAction: MFAAction.WalletWaasExport,
});
if (isMfaRequired) {
await promptMfaAuth({ createMfaToken: true });
}
await primaryWallet.exportWaasPrivateKey();
After — useStepUpAuthentication with requestedScopes: import { useStepUpAuthentication } from '@dynamic-labs/sdk-react-core';
import { TokenScope } from '@dynamic-labs/sdk-api-core';
const { isStepUpRequired, promptStepUpAuth } = useStepUpAuthentication();
if (await isStepUpRequired({ scope: TokenScope.Walletexport })) {
await promptStepUpAuth({
requestedScopes: [TokenScope.Walletexport],
});
}
// Token is stored — SDK attaches it automatically
await primaryWallet.exportWaasPrivateKey();
Before — client.ui.mfa.show with createMfaToken: import { MFAAction } from '@dynamic-labs/sdk-api-core';
const isMfaRequired = await client.mfa.isRequiredForAction({
mfaAction: MFAAction.WalletWaasExport,
});
if (isMfaRequired) {
await client.ui.mfa.show({ createMfaToken: true });
}
await primaryWallet.exportWaasPrivateKey();
After — client.stepUpAuth.promptStepUpAuth with requestedScopes: import { TokenScope } from '@dynamic-labs/sdk-api-core';
const isRequired = await client.stepUpAuth.isStepUpRequired({
scope: TokenScope.Walletexport,
});
if (isRequired) {
await client.stepUpAuth.promptStepUpAuth({
requestedScopes: [TokenScope.Walletexport],
});
}
// Token is stored — SDK attaches it automatically
await primaryWallet.exportWaasPrivateKey();
Flutter did not have a built-in action-based MFA UI. Use promptStepUpAuth to add step-up verification: import 'package:dynamic_sdk/dynamic_sdk.dart';
final isRequired = await DynamicSDK.instance.stepUpAuth
.isStepUpRequired('wallet:export');
if (isRequired) {
await DynamicSDK.instance.stepUpAuth.promptStepUpAuth(
requestedScopes: ['wallet:export'],
);
}
// Token is stored — SDK attaches it automatically
await performExport();
Headless TOTP
React
JavaScript
React Native
Flutter
Before — useMfa with authenticateDevice and createMfaToken: import { useMfa, useIsMfaRequiredForAction } from "@dynamic-labs/sdk-react-core";
import { MFAAction } from '@dynamic-labs/sdk-api-core';
const { authenticateDevice } = useMfa();
const isMfaRequiredForAction = useIsMfaRequiredForAction();
const requires = await isMfaRequiredForAction({
mfaAction: MFAAction.WalletWaasExport,
});
if (requires) {
await authenticateDevice({
code: totpCode,
createMfaToken: { singleUse: true },
});
}
After — useStepUpAuthentication with verifyTotpMfa: import { useStepUpAuthentication } from '@dynamic-labs/sdk-react-core';
import { TokenScope } from '@dynamic-labs/sdk-api-core';
const { isStepUpRequired, verifyTotpMfa } = useStepUpAuthentication();
if (await isStepUpRequired({ scope: TokenScope.Walletexport })) {
await verifyTotpMfa({
code: totpCode,
requestedScopes: [TokenScope.Walletexport],
});
}
Before — authenticateTotpMfaDevice with createMfaTokenOptions: import { isMfaRequiredForAction, authenticateTotpMfaDevice, MFAAction } from '@dynamic-labs-sdk/client';
const required = await isMfaRequiredForAction({ mfaAction: MFAAction.WalletWaasExport });
if (required) {
await authenticateTotpMfaDevice({
code: '123456',
createMfaTokenOptions: { singleUse: true },
});
}
After — same function with requestedScopes: import { checkStepUpAuth, authenticateTotpMfaDevice } from '@dynamic-labs-sdk/client';
import { TokenScope } from '@dynamic-labs/sdk-api-core';
const { isRequired } = await checkStepUpAuth({ scope: TokenScope.Walletexport });
if (isRequired) {
await authenticateTotpMfaDevice({
code: '123456',
requestedScopes: [TokenScope.Walletexport],
});
}
Before — client.mfa.authenticateDevice with createMfaToken: import { MFAAction } from '@dynamic-labs/sdk-api-core';
const requires = await client.mfa.isRequiredForAction({
mfaAction: MFAAction.WalletWaasExport,
});
if (requires) {
await client.mfa.authenticateDevice({
code: totpCode,
createMfaToken: { singleUse: true },
});
}
After — client.stepUpAuth.verifyTotpMfa with requestedScopes: import { TokenScope } from '@dynamic-labs/sdk-api-core';
const isRequired = await client.stepUpAuth.isStepUpRequired({
scope: TokenScope.Walletexport,
});
if (isRequired) {
await client.stepUpAuth.verifyTotpMfa({
code: totpCode,
requestedScopes: [TokenScope.Walletexport],
});
}
import 'package:dynamic_sdk/dynamic_sdk.dart';
final isRequired = await DynamicSDK.instance.stepUpAuth
.isStepUpRequired('wallet:export');
if (isRequired) {
await DynamicSDK.instance.stepUpAuth.verifyTotpMfa(
code: totpCode,
requestedScopes: ['wallet:export'],
);
}
Headless Passkey
React
JavaScript
React Native
Flutter
Before — useAuthenticatePasskeyMFA with createMfaToken: import {
useAuthenticatePasskeyMFA,
useGetPasskeys,
useIsMfaRequiredForAction,
useRegisterPasskey,
} from "@dynamic-labs/sdk-react-core";
import { MFAAction } from '@dynamic-labs/sdk-api-core';
const authenticatePasskeyMFA = useAuthenticatePasskeyMFA();
const getPasskeys = useGetPasskeys();
const registerPasskey = useRegisterPasskey();
const isMfaRequiredForAction = useIsMfaRequiredForAction();
const requires = await isMfaRequiredForAction({
mfaAction: MFAAction.WalletWaasExport,
});
if (requires) {
const passkeys = await getPasskeys();
if (passkeys.length === 0) {
await registerPasskey();
}
await authenticatePasskeyMFA({
createMfaToken: { singleUse: false },
});
}
After — useStepUpAuthentication with verifyPasskeyMfa: import { useStepUpAuthentication } from '@dynamic-labs/sdk-react-core';
import { TokenScope } from '@dynamic-labs/sdk-api-core';
const { isStepUpRequired, verifyPasskeyMfa } = useStepUpAuthentication();
if (await isStepUpRequired({ scope: TokenScope.Walletexport })) {
await verifyPasskeyMfa({
requestedScopes: [TokenScope.Walletexport],
});
}
Before — authenticatePasskeyMFA with createMfaToken: import { isMfaRequiredForAction, authenticatePasskeyMFA, MFAAction } from '@dynamic-labs-sdk/client';
const required = await isMfaRequiredForAction({ mfaAction: MFAAction.WalletWaasExport });
if (required) {
await authenticatePasskeyMFA({
createMfaToken: { singleUse: true },
});
}
After — same function with requestedScopes: import { checkStepUpAuth, authenticatePasskeyMFA } from '@dynamic-labs-sdk/client';
import { TokenScope } from '@dynamic-labs/sdk-api-core';
const { isRequired } = await checkStepUpAuth({ scope: TokenScope.Walletexport });
if (isRequired) {
await authenticatePasskeyMFA({
requestedScopes: [TokenScope.Walletexport],
});
}
Before — client.passkeys.authenticateMFA with createMfaToken: import { MFAAction } from '@dynamic-labs/sdk-api-core';
const requires = await client.mfa.isRequiredForAction({
mfaAction: MFAAction.WalletWaasExport,
});
if (requires) {
const passkeys = await client.passkeys.get();
if (passkeys.length === 0) {
await client.passkeys.register();
}
await client.passkeys.authenticateMFA({
createMfaToken: { singleUse: false },
});
}
After — client.stepUpAuth.verifyPasskeyMfa with requestedScopes: import { TokenScope } from '@dynamic-labs/sdk-api-core';
const isRequired = await client.stepUpAuth.isStepUpRequired({
scope: TokenScope.Walletexport,
});
if (isRequired) {
await client.stepUpAuth.verifyPasskeyMfa({
requestedScopes: [TokenScope.Walletexport],
});
}
import 'package:dynamic_sdk/dynamic_sdk.dart';
final isRequired = await DynamicSDK.instance.stepUpAuth
.isStepUpRequired('wallet:export');
if (isRequired) {
await DynamicSDK.instance.stepUpAuth.verifyPasskeyMfa(
requestedScopes: ['wallet:export'],
);
}
Migration checklist
React
JavaScript
React Native
Flutter
- Upgrade to React SDK
4.76.0 or later
- Replace
useMfa / useAuthenticatePasskeyMFA / usePromptMfaAuth with useStepUpAuthentication
- Replace
createMfaToken with requestedScopes using the appropriate TokenScope
- Replace
useIsMfaRequiredForAction with isStepUpRequired
- Test the step-up flow end-to-end for each protected action
- Accept the minimum API version
2026_04_01 in your dashboard
For the full step-up authentication reference (all verification methods, scopes, token lifecycle), see Step-up authentication.
- Upgrade to JavaScript SDK
0.24.1 or later
- Replace
isMfaRequiredForAction with checkStepUpAuth
- Replace
createMfaToken / createMfaTokenOptions with requestedScopes on authenticateTotpMfaDevice and authenticatePasskeyMFA
- Test the step-up flow end-to-end for each protected action
- Accept the minimum API version
2026_04_01 in your dashboard
For the full step-up authentication reference (all verification methods, scopes, token lifecycle), see Step-up authentication.
- Upgrade to React Native SDK
4.76.0 or later
- Replace
client.mfa.isRequiredForAction with client.stepUpAuth.isStepUpRequired
- Replace
client.mfa.authenticateDevice with client.stepUpAuth.verifyTotpMfa
- Replace
client.passkeys.authenticateMFA with client.stepUpAuth.verifyPasskeyMfa
- Replace
client.ui.mfa.show with client.stepUpAuth.promptStepUpAuth
- Test the step-up flow end-to-end for each protected action
- Accept the minimum API version
2026_04_01 in your dashboard
For the full step-up authentication reference (all verification methods, scopes, token lifecycle), see Step-up authentication.
- Upgrade to Flutter SDK
1.2.10 or later
- Implement step-up checks with
DynamicSDK.instance.stepUpAuth.isStepUpRequired
- Add verification flows using
promptStepUpAuth, verifyTotpMfa, or verifyPasskeyMfa
- Test the step-up flow end-to-end for each protected action
- Accept the minimum API version
2026_04_01 in your dashboard
For the full step-up authentication reference (all verification methods, scopes, token lifecycle), see Step-up authentication.