Add MFA
Turn on multi-factor authentication, require it for the people who need it, and give every user a safe way back in if they lose a device.
OrthID supports time-based one-time passwords (TOTP) from any authenticator app and one-time passcodes (OTP) sent over SMS or email. You can offer MFA as optional, or enforce it across an organisation or for a specific role. This guide covers enabling factors, enforcing a policy, recovery codes, and the user enrolment flow.
1. Enable factors
Factors are configured per environment. Enable the ones you want to offer, then set a policy to control who must use them. The example below enables TOTP and email OTP, and turns off SMS.
import { orthid } from "@orthid/sdk";
// Enable the factors users may enrol.
await orthid.mfa.setFactors({
totp: true, // authenticator apps (recommended)
otpEmail: true, // one-time passcode by email
otpSms: false, // disabled: SMS is the weakest factor
});2. Enforce a policy
A policy decides who is required to have MFA. Scope it to an organisation, to one or more roles, or to everyone in the environment. When a policy applies to a user, OrthID blocks any sensitive session step until at least one factor is enrolled.
import { orthid } from "@orthid/sdk";
// Require MFA for every admin in this organisation.
await orthid.mfa.setPolicy({
organizationId: "org_clinic_42",
enforce: "required", // "optional" | "required"
appliesToRoles: ["admin", "clinician"],
// Give existing users a window to enrol before they are locked out.
gracePeriodHours: 72,
});
// Or require MFA for everyone in the environment.
await orthid.mfa.setPolicy({ enforce: "required" });Policies are evaluated at session time. A user who matches a required policy and has not enrolled is sent into the enrolment flow on their next sign-in; until they finish, OrthID issues a restricted session that cannot reach protected routes.
3. Recovery codes
When a user enrols their first factor, OrthID generates a set of single-use recovery codes. Each code logs the user in once and is then burned. Generate or regenerate them through the API if you build your own enrolment UI.
import { orthid } from "@orthid/sdk";
// Issue a fresh set of 10 single-use recovery codes.
const { codes } = await orthid.mfa.generateRecoveryCodes({
userId: "user_8sQ1",
count: 10,
});
// Show these to the user ONCE. OrthID only stores their hashes.
console.log(codes);
// => ["7P2K-9QXM", "4LWD-1FZB", ...]4. The user enrolment flow
With the prebuilt components, enrolment is automatic. The hosted <UserButton/> profile exposes a security panel where users can add a factor, and the sign-in flow steps a user through enrolment whenever a required policy applies. The flow is:
- The user scans the TOTP QR code, or requests an email passcode.
- They confirm the factor by entering one live code.
- OrthID shows the recovery codes and asks the user to save them.
- On every later sign-in the user completes the second step after their password or passkey.
If you build a custom UI, drive the same steps with the MFA enrolment API.
import { orthid } from "@orthid/sdk";
// Start TOTP enrolment: returns a secret and an otpauth:// URI for the QR code.
const enrolment = await orthid.mfa.startEnrollment({
userId: "user_8sQ1",
factor: "totp",
});
// enrolment.qrCodeUri -> render as a QR image
// enrolment.secret -> offer as a manual fallback
// Confirm with the first live code from the user's app.
await orthid.mfa.confirmEnrollment({
userId: "user_8sQ1",
enrollmentId: enrolment.id,
code: "204815",
});enforce: "optional" and a small pilot role first. Once enrolment is healthy, switch to required with a grace period so existing users are not locked out mid-session.Next steps
- Enable SSO so enterprise tenants bring their own identity provider and MFA.
- Sessions explains how OrthID tracks a signed-in actor and when a step-up is required.