4.5 KiB
TOTP End-to-End Test Proposal
Test Objective
Test ALL aspects of TOTP functionality regardless of current state (TOTP enabled or disabled).
Test Flow
Scenario A: TOTP Currently Enabled (Bob already enrolled)
-
Login with email/password
- Response:
requires_totp: true
- Response:
-
Get Secret from DB (or use environment variable)
- Since secret is encrypted/hashed in DB, we need to either:
- Store it in environment/file from previous enrollment, OR
- User provides it as input, OR
- Use backup code from previous enrollment
- Since secret is encrypted/hashed in DB, we need to either:
-
Generate TOTP Code using stored secret/backup code
-
Verify TOTP to complete login
- Endpoint:
/auth/totp/verify - Get auth_token
- Endpoint:
-
Check TOTP Status
- Endpoint:
/auth/totp/status - Confirm:
totp_enabled: true
- Endpoint:
-
Disable TOTP
- Endpoint:
/auth/totp/disable - Provide password
- Endpoint:
-
Logout
-
Continue to Scenario B steps 2-14
Scenario B: TOTP Currently Disabled (or after completing Scenario A)
-
Login with email/password
- Response:
token(no TOTP required)
- Response:
-
Check TOTP Status
- Endpoint:
/auth/totp/status - Confirm:
totp_enabled: false
- Endpoint:
-
Enroll in TOTP
- Endpoint:
/auth/totp/enroll - Store: secret, backup_codes, provisioning_uri, qr_code
- Endpoint:
-
Generate TOTP Code from new secret
- Use timezone-aware UTC
-
Verify Enrollment
- Endpoint:
/auth/totp/verify-enrollment - Provide generated code
- Endpoint:
-
Check TOTP Status Again
- Confirm:
totp_enabled: true - Confirm:
backup_codes_remaining: 10 - Confirm:
verified_atis set
- Confirm:
-
Logout
-
Login with email/password
- Response:
requires_totp: true
- Response:
-
Generate TOTP Code from stored secret
-
Verify TOTP to complete login
- Endpoint:
/auth/totp/verify - Get auth_token
- Endpoint:
-
Confirm Logged In
- Endpoint:
/auth/me - Verify user data returned
- Endpoint:
-
Test Backup Code (new login)
- Logout
- Login with email/password
- Use backup code instead of TOTP
- Endpoint:
/auth/totp/verifywithis_backup_code: true
-
Check Backup Codes Remaining
- Should be 9 (one consumed)
-
Regenerate Backup Codes
- Endpoint:
/auth/totp/regenerate-backup-codes - Provide password
- Get new set of 10 codes
- Endpoint:
Implementation Strategy
Secret Persistence Between Test Runs
Option 1: Environment Variable (Recommended)
import os
# Save secret after first successful enrollment
SECRET_FILE = ".totp_test_secret"
if os.path.exists(SECRET_FILE):
with open(SECRET_FILE) as f:
data = json.load(f)
known_secret = data.get("secret")
known_backup_codes = data.get("backup_codes", [])
else:
known_secret = None
known_backup_codes = []
# After enrollment, save for next run
with open(SECRET_FILE, 'w') as f:
json.dump({
"secret": new_secret,
"backup_codes": new_backup_codes
}, f)
Option 2: Test Database State
- Include SQL query to fetch secret from DB (if stored in plain text for testing)
- Or decrypt if encrypted
Option 3: Manual Input
- Prompt user for secret/backup code if TOTP already enabled
- Less automated but more flexible
Expected Assertions
- ✅ Login without TOTP works when disabled
- ✅ Enrollment generates secret, QR code, backup codes
- ✅ Enrollment verification accepts valid TOTP code
- ✅ TOTP status shows enabled after verification
- ✅ Login requires TOTP when enabled
- ✅ TOTP verification works during login
- ✅ Backup code works for authentication
- ✅ Backup codes decrement when used
- ✅ Backup code regeneration works
- ✅ TOTP disable works with correct password
- ✅ Login works without TOTP after disabling
Test Data Management
Store in .totp_test_data.json (gitignored):
{
"user": "bob@acme-corp.com",
"secret": "BWAQAP55...",
"backup_codes": ["code1", "code2", ...],
"enrollment_date": "2026-01-14T03:12:00Z",
"last_test_run": "2026-01-14T03:15:00Z"
}
Error Handling
- Connection errors → clear message about server not running
- 401 errors → check if token/credentials are correct
- TOTP code failures → check time synchronization
- Backup code failures → check if already used
Success Criteria
Test passes when:
- All 14 steps complete without errors
- All assertions pass
- Test can run multiple times (idempotent)
- Works from both initial states (TOTP enabled/disabled)
Please review this proposal. Once approved, I'll implement it.