Skip to content

Authentication & session configuration

Each environment decides how its users authenticate and how long their sessions last. You configure this from the dashboard under Settings; the SDK reads the environment’s public config on load and renders the sign-in / sign-up surfaces to match, and the server enforces the same rules on every request.

Settings → User & authentication exposes five independent toggles:

  • Email sign-up — allow new users to create an account with email and password. Off makes sign-up OAuth-only: the SDK hides the email form on <SignUp> and shows just the provider buttons.
  • Email sign-in — allow users to sign in with email and password. Off makes sign-in OAuth-only: the SDK hides the email form on <SignIn>.
  • Passwordless email code — let users sign in with a 6-digit code emailed to them instead of a password. Off by default, unlike every other toggle here: it adds a new way into existing accounts, so it is never switched on for you. See Passwordless email-code sign-in.
  • Verify email at sign-up — require a 6-digit emailed code before the account is created. When off, <SignUp> skips the code step entirely: the account and session are created immediately and the user is signed in with an as-yet-unverified email.
  • Require email address — every user must carry an email, enforced on every path. An OAuth or MitID sign-up whose provider returns no verified email pauses on a continuation screen: the user adds an address, receives a 6-digit code, and the account is created only once the code checks out — so the address is verified from the first moment it exists. The backend API refuses to create a user without an email (422 email_required). And a sign-in for an existing account that carries no email pauses on the same continuation until the user adds and verifies one — after the password, emailed code, or second factor has already been checked, never before. Off by default.
  • Require name — every user must carry a name, enforced on every path. <SignUp> and the invitation sign-up render a required name field; the backend API refuses a nameless user (422 name_required); an OAuth or MitID sign-up whose provider returns no name claims (a name-protected MitID identity, for example) pauses on the continuation screen and asks for a first and last name; and a sign-in for an existing nameless account pauses the same way until a name is entered. Off by default.

With Require email address off (the default), a user who signs in through MitID — or any provider that returns no email claim, or one whose address came back unverified — gets an account with no email on it. That is a supported state, not an error, and two things behave differently for those users:

  • <UserDashboard> asks them to add an address instead of telling them to check their inbox. Nothing was emailed, so there is nothing to verify or resend.
  • Account deletion is unavailable until they add one. Deletion is confirmed through a one-time link we email to the address on file, so the flow has nowhere to send it; the dialog says so and the server refuses the request.

They can add an address themselves under Email addresses in <UserProfile>; it goes through the normal verification, and both behaviours above resolve once it is verified. Turn Require email address on if your app cannot support email-less accounts at all — new MitID sign-ups then collect and verify an address on the continuation screen before the account is created, and existing email-less users are asked for one at their next sign-in, so MitID stays usable.

With Passwordless email code on, <SignIn> offers Email me a sign-in code alongside the password field. The user enters their address, receives a 6-digit code, types it back into the same tab, and is signed in.

It is a sign-in method only. It never creates an account, so it is not a substitute for Email sign-up — an environment still needs a way for new users to register.

Three behaviours worth knowing before you turn it on:

  • Requesting a code always answers the same way, whether or not the address has an account. The endpoint is unauthenticated, so a “no such user” response would let anyone check which addresses are registered with you. Your UI should say “if an account exists, we sent a code” and mean it — the SDK cannot tell you which case it was, by design.
  • It does not bypass multi-factor authentication. An emailed code proves control of the mailbox, which is a first factor. A user with an authenticator app is still challenged for their second factor exactly as on password sign-in.
  • Codes are short-lived and single-use: they expire after 10 minutes, allow five wrong guesses, and requesting a new one immediately retires the previous one.

You can run an environment fully passwordless by turning Email sign-in off and leaving this on. <SignIn> then asks for the address and goes straight to the code step, with no password field at all.

The email itself is yours to brand: Settings → Email templates → Sign-in code edits its subject and body per locale, like every other authentication email. It is a required template rather than an optional one — with passwordless on it is the only way those users can finish signing in, so it cannot be switched off — and its body must keep the code variable, or the email ships without the one thing the recipient needs.

You cannot disable both email sign-up and sign-in unless an OAuth provider is enabled to fall back on — otherwise users would have no way to authenticate. The dashboard warns inline, and the API refuses the change with a clear error.

Passwordless email code counts as a sign-in path for this check, so an environment with it on may turn Email sign-in off. It does not count as a sign-up path.

Settings → Sessions controls how long a signed-in session stays valid, with two independent limits (at least one must be set):

  • Inactivity timeout — the session expires after this much inactivity. It slides forward on activity, so an active user stays signed in.
  • Maximum lifetime — a hard cap on session age regardless of activity.

With only a maximum set (the default is 30 days), sessions have a fixed lifetime. Add an inactivity timeout to expire idle sessions sooner while keeping active ones alive.

To customize the claims inside the session token, use JWT templates.

The same page has a Multi-session toggle. When on, end users can be signed in to several accounts at once in one browser and switch between them:

  • <UserButton> picks it up automatically: its menu lists the other signed-in accounts and gains an Add account item that opens the standard sign-in card in a dialog.
  • Signing out ends only the current account’s session; the SDK switches to the most recently used remaining account, and the user lands signed out only when no accounts remain.
  • For custom UI, use the headless useSessionList() hook.
  • Switching or adding an account changes who is signed in, so the SDK reloads the page by default (to signInUrl, else /) to rebuild caches for the new user. Opt into an in-page swap with onActiveSessionChange.

The SDK fetches the environment’s public config once on load, so <SignIn> and <SignUp> render the right surfaces without any extra configuration in your app. If you build your own UI with the headless hooks, useSignUp resolves to a success status directly (no code step) when verification is disabled — signing the user in automatically unless you pass autoSignIn: false — and you can read the enabled methods from the auth context to render conditionally.