Skip to content

Multi-Factor Authentication (MFA)

Learn how to add TOTP-based multi-factor authentication to your application for enhanced security.

MFA TOTP two-factor 2FA authenticator security multi-factor

Multi-Factor Authentication adds an extra layer of security by requiring a verification code from an authenticator app (e.g., Authy, Google Authenticator) in addition to the user’s email and password.

To enable MFA, navigate to Settings -> Authentication and enable Multi-Factor Authentication. You can also configure it using the nhost.toml file:

nhost.toml
[auth.totp]
enabled = true

Once MFA is enabled for your project, individual users can activate it on their account. This is a two-step process:

Request a TOTP secret and QR code for the user to scan with their authenticator app:

const response = await nhost.auth.changeUserMfa();
// Display the QR code image for the user to scan
const imageUrl = response.body.imageUrl;
// Or show the totpSecret for manual entry
const totpSecret = response.body.totpSecret;

After the user scans the QR code, they enter the 6-digit verification code from their authenticator app to confirm activation:

await nhost.auth.verifyChangeUserMfa({
activeMfaType: 'totp',
code: '123456', // 6-digit code from authenticator app
});
sequenceDiagram
autonumber
actor U as User
participant C as Client
participant A as Nhost Auth
participant G as Authenticator App
U-->A: Authenticated
C->>+A: GET /mfa/totp/generate
A->>-C: QR code image URL + TOTP secret
C->>U: Display QR code
U->>+G: Scan QR code
G->>-U: 6-digit TOTP code
C->>+A: POST /user/mfa
Note right of C: TOTP code + activeMfaType: "totp"
A->>A: Verify code and activate MFA
A->>-C: OK

When a user with MFA enabled signs in with email and password, the server returns a ticket instead of a session. The client must then prompt for a TOTP code and verify it to complete sign-in.

const response = await nhost.auth.signInEmailPassword({
email: 'joe@example.com',
password: 'secret-password',
});
if (response.body?.mfa) {
// MFA is required — store the ticket and prompt for TOTP
const ticket = response.body.mfa.ticket;
// Navigate to MFA verification page
}
const response = await nhost.auth.verifySignInMfaTotp({
ticket: ticket, // from step 1
otp: '123456', // 6-digit code from authenticator app
});
// response.body.session contains the access + refresh tokens
sequenceDiagram
autonumber
actor U as User
participant C as Client
participant A as Nhost Auth
participant G as Authenticator App
U->>C: Enter email + password
C->>+A: POST /signin/email-password
A->>-C: MFA ticket
C->>U: Prompt for TOTP code
U->>+G: Open authenticator app
G->>-U: 6-digit TOTP code
U->>C: Enter TOTP code
C->>+A: POST /signin/mfa/totp
Note right of C: ticket + TOTP code
A->>A: Verify TOTP
A->>-C: Session (access + refresh tokens)

Users can disable MFA by providing a current TOTP code from their authenticator app:

await nhost.auth.verifyChangeUserMfa({
activeMfaType: '', // empty string disables MFA
code: '123456', // current 6-digit code from authenticator app
});