Prerequisites
Before this page: create and initialize a Dynamic client (see Creating a Dynamic client and Initializing the Dynamic client), and get the user authenticated with email/SMS OTP, social, or passkeys.What you’ll build
Authentication proves who the user is. It doesn’t guarantee they’re ready to use your app. Depending on your dashboard configuration, a just-signed-in user may still need to:- Complete required fields — profile information you’ve marked required (name, email, custom fields).
- Enroll in MFA — set up a TOTP authenticator app and save recovery codes. See MFA.
- Register their device — confirm the device via an emailed link. See Device registration.
- Get an embedded wallet — create their embedded wallet if your app uses them.
Not every app needs every step. If you haven’t enabled MFA or device registration in the dashboard, those checks simply return
false — build only the steps your app requires.The setup flow
After login, run a chain of checks. Each check answers “does the user still need to do this?” — if yes, show that step’s UI, wait for the user to finish, then move to the next check.Detecting what’s pending
Each check is a single call. Compose them into one object so the rest of your UI can ask “what’s left?”:Building the flow
- TypeScript
- React
Run each step in order. When a step needs the user, render your UI, wait for them to finish, then continue. The
show* functions below are your implementation — the SDK owns the logic, you own the screens.updateUser returns an OTPVerification when a sensitive field (email or phone) changes, because the new value must be verified with a code. For plain profile fields it resolves to undefined. If you collect email/phone here, follow up with the OTP verification flow.Device registration: completing the redirect
Device registration emails the user a link. When they click it they return to your app with a token in the URL — detect and complete it on every page load, the same way you handle social redirects:Handling errors
Each step can fail independently. Keep the user on the current step when its call rejects, rather than dropping them back to the start.Alternative approaches
Gate access without per-step UI
If you don’t need a wizard, just block the app until the user is ready by reusingisSetupComplete():
- TypeScript
- React
React to completion from another tab
Listen foruserChanged to advance when the user finishes a step elsewhere (e.g. clicking the device-registration email in another tab):
Skip steps with your own rules
The chain is yours — branch it on your business logic. For example, only require MFA for users who will access sensitive features:See also
- Email & SMS OTP sign-in — get the user authenticated first
- MFA — MFA enrollment and verification reference
- Device registration — the device registration flow
- Creating embedded wallets — embedded wallet creation reference
- Authentication concepts — users, sessions, and credentials