# Security: 2FA, passkeys, sessions

## Two-factor authentication

Two-factor authentication, passkeys and your security question are on the **Sessions** page (`/sessions`). To enable two-factor authentication:

- Scan the QR code with an authenticator app (Google Authenticator, 1Password, Authy and others) and enter the 6-digit code to confirm.
- Save the **backup codes** somewhere safe. Each one works once instead of a code, if you lose your phone.

From then on, signing in asks for a code after your password. You can create new backup codes or disable 2FA after confirming it is you.

## Passkeys

A passkey signs you in with your device (fingerprint, face or PIN) instead of a password. Add one on **Sessions**; you can add several and remove them. If you lose the device, sign in with your password (and 2FA code or backup code) and remove the old passkey.

## Sessions

The same page lists where you are signed in, with device and IP address. Sign out any session you do not recognise, then change your password.

## Security question

Your provider may ask you to set a security question, used to confirm who you are when you contact support.

| Method | Path | Summary |
|---|---|---|
| GET | `/api/v1/auth/mfa` |  |
| POST | `/api/v1/auth/mfa/backup-codes` | Replace all backup codes; returned once. |
| POST | `/api/v1/auth/mfa/disable` | Turn 2FA off; needs the password and a current code (or a backup code). |
| POST | `/api/v1/auth/mfa/enable` |  |
| POST | `/api/v1/auth/mfa/setup` | Start enrolment: a fresh pending secret, replaced on each call until enabled. |
| POST | `/api/v1/auth/mfa/verify` | Second login step. Max 5 attempts per challenge, 5 minute lifetime. |
| GET | `/api/v1/auth/passkeys` |  |
| POST | `/api/v1/auth/passkeys/discover/finish` |  |
| POST | `/api/v1/auth/passkeys/discover/start` | Usernameless sign-in: empty `allowCredentials`, the authenticator picks a |
| POST | `/api/v1/auth/passkeys/login/finish` | Passwordless sign-in. A user-verified passkey counts as both factors. |
| POST | `/api/v1/auth/passkeys/login/start` |  |
| POST | `/api/v1/auth/passkeys/reauth/finish` | Step-up with a passkey instead of password + code. |
| POST | `/api/v1/auth/passkeys/reauth/start` |  |
| POST | `/api/v1/auth/passkeys/register/finish` |  |
| POST | `/api/v1/auth/passkeys/register/start` | Enrolment needs the password (and 2FA code when enabled) again. |
| DELETE | `/api/v1/auth/passkeys/{id}` |  |
| POST | `/api/v1/auth/password/change` | change password |
| POST | `/api/v1/auth/password/forgot` |  |
| POST | `/api/v1/auth/password/reset` |  |
| DELETE | `/api/v1/auth/sessions` | Sign out every other device; the calling session stays valid. |
| GET | `/api/v1/auth/sessions` |  |
| DELETE | `/api/v1/auth/sessions/{id}` |  |

Full request and response details: [HTTP API](developers/api.md).

