Backup Codes
Generate and manage MFA backup codes in HelloJohn — recovery codes for when users lose access to their primary MFA device.
Backup codes are single-use recovery codes generated when a user enrolls in MFA. They're a last resort for when the user loses their MFA device.
How backup codes work
- Generated automatically when a user enrolls their first MFA method
- Each code is single-use — using a code invalidates it
- 10 codes are generated by default (configurable)
- Codes are hashed server-side — HelloJohn cannot recover them if lost
Backup codes are only shown once at enrollment time. If a user loses their codes, an admin must regenerate them — the existing codes are invalidated in the process.
Generating backup codes
Backup codes are generated automatically when a user completes their first MFA enrollment. They're returned in the enrollment response:
{
"method_id": "mfa_01HX...",
"backup_codes": [
"ABCD-EFGH",
"IJKL-MNOP",
"QRST-UVWX",
"YZAB-CDEF",
"GHIJ-KLMN",
"OPQR-STUV",
"WXYZ-1234",
"5678-9012",
"3456-7890",
"1234-5678"
]
}Display these to the user and encourage them to save them in a secure location (password manager, printed copy).
Using a backup code
When a user can't access their MFA device, they use a backup code instead:
POST /v2/auth/mfa/backup-code/verify
Content-Type: application/json
{
"challenge_id": "challenge_01HX...",
"code": "ABCD-EFGH"
}Response 200 OK — session issued. The used code is invalidated immediately.
SDK integration
import { useMFA } from '@hellojohn/react'
function BackupCodeInput({ challengeId }: { challengeId: string }) {
const { submitBackupCode } = useMFA()
return (
<form onSubmit={e => {
e.preventDefault()
submitBackupCode(challengeId, (e.target as any).code.value)
}}>
<p>Enter one of your backup codes:</p>
<input
name="code"
type="text"
placeholder="XXXX-XXXX"
pattern="[A-Z0-9]{4}-[A-Z0-9]{4}"
/>
<button type="submit">Use backup code</button>
</form>
)
}Regenerating backup codes
Users can regenerate backup codes from their account settings (invalidates all existing codes):
POST /v2/auth/mfa/backup-codes/regenerate
Authorization: Bearer {access_token}Response:
{
"backup_codes": ["NEW1-XXXX", "NEW2-XXXX", ...]
}Admin override (for users who lost all access):
POST /v2/admin/users/{userId}/mfa/backup-codes/regenerate
Authorization: Bearer $ADMIN_TOKENAfter an admin regenerates backup codes, the user should be notified to save the new codes. The old codes are immediately invalidated.
Configuring backup code count
MFA_BACKUP_CODES_COUNT=10 # default: 10Or per tenant:
PATCH /v2/admin/tenants/{tenantId}/auth/config
{
"mfa_backup_codes_count": 8
}Checking remaining backup codes
Users can see how many valid backup codes they have left:
GET /v2/auth/mfa/backup-codes/status
Authorization: Bearer {access_token}{
"total": 10,
"used": 3,
"remaining": 7
}When remaining is low (≤ 2), prompt the user to regenerate.