How Recovery Codes Work
Recovery codes are:- Automatically generated when a user enables their first MFA method
- Single-use - each code can only be used once
- Numeric - typically 8-digit codes by default
- Cryptographically secure - generated using HMAC-SHA1 with a random seed
Configuration
Recovery codes are enabled by default:settings.py
Settings Reference
MFA_RECOVERY_CODE_COUNT
Default: 10
The number of recovery codes to generate for each user.
MFA_RECOVERY_CODE_DIGITS
Default: 8
The number of digits in each recovery code.
Longer codes are more secure but harder to type. 8 digits provides a good balance between security and usability.
URL Endpoints
Recovery code URLs are available at:/accounts/mfa/recovery-codes/- View unused recovery codes/accounts/mfa/recovery-codes/generate/- Generate new recovery codes/accounts/mfa/recovery-codes/download/- Download codes as text file
Automatic Generation
Recovery codes are automatically generated when a user activates their first MFA method:Viewing Recovery Codes
Users can view their unused recovery codes at any time (requires reauthentication):templates/mfa/recovery_codes/index.html
Downloading Recovery Codes
Users can download their codes as a plain text file:Regenerating Recovery Codes
Users can generate new recovery codes (invalidates old ones):templates/mfa/recovery_codes/generate.html
Programmatic Usage
Generate Recovery Codes
Validate a Recovery Code
Check Remaining Codes
Regenerate Codes
How Codes Are Generated
Recovery codes are generated using HMAC-SHA1:Storage Format
Recovery codes are stored in theAuthenticator model:
used_mask is a bitmask where each bit represents whether a code has been used:
- Bit 0 = first code
- Bit 1 = second code
- etc.
Encryption
The seed is encrypted before storage:myapp/adapter.py
settings.py
Migration Support
If you’re migrating from another system with existing recovery codes:- Are stored as an encrypted list
- Are removed from the list when used
- Don’t use the seed-based generation
Forms Customization
Override the recovery code generation form:settings.py
myapp/forms.py
User Experience Best Practices
Show Codes Immediately After Generation
After enabling MFA, redirect users to view their recovery codes:Warn When Codes Are Low
Download Instructions
Encourage users to download and securely store their codes:Security Considerations
Single Use
Each code can only be used once. After validation, the code is marked as used:Secure Storage
Users should store recovery codes:- In a password manager
- In a secure physical location (safe, lockbox)
- Never in plain text on their device
Regeneration
When codes are regenerated:- All old codes are invalidated
- A new seed is generated
- Users must download/save the new codes
Testing
Generate Test Codes
Test Code Validation
Common Issues
Codes Not Generated
Ensure recovery codes are enabled:Can’t View Codes
Check that the user has MFA enabled:Codes Already Used
If all codes are used, users must:- Use an alternative MFA method (TOTP, WebAuthn) to log in
- Generate new recovery codes
- Disable MFA for the user in Django admin
- Or generate new codes programmatically
Related
- TOTP Authentication - Time-based one-time passwords
- WebAuthn - Hardware key authentication
- Configuration - All MFA settings
