Files
gatehouse-api/TOTP_TEST_PROPOSAL.md
T
2026-01-14 18:06:26 +10:30

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)

  1. Login with email/password

    • Response: requires_totp: true
  2. 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
  3. Generate TOTP Code using stored secret/backup code

  4. Verify TOTP to complete login

    • Endpoint: /auth/totp/verify
    • Get auth_token
  5. Check TOTP Status

    • Endpoint: /auth/totp/status
    • Confirm: totp_enabled: true
  6. Disable TOTP

    • Endpoint: /auth/totp/disable
    • Provide password
  7. Logout

  8. Continue to Scenario B steps 2-14

Scenario B: TOTP Currently Disabled (or after completing Scenario A)

  1. Login with email/password

    • Response: token (no TOTP required)
  2. Check TOTP Status

    • Endpoint: /auth/totp/status
    • Confirm: totp_enabled: false
  3. Enroll in TOTP

    • Endpoint: /auth/totp/enroll
    • Store: secret, backup_codes, provisioning_uri, qr_code
  4. Generate TOTP Code from new secret

    • Use timezone-aware UTC
  5. Verify Enrollment

    • Endpoint: /auth/totp/verify-enrollment
    • Provide generated code
  6. Check TOTP Status Again

    • Confirm: totp_enabled: true
    • Confirm: backup_codes_remaining: 10
    • Confirm: verified_at is set
  7. Logout

  8. Login with email/password

    • Response: requires_totp: true
  9. Generate TOTP Code from stored secret

  10. Verify TOTP to complete login

    • Endpoint: /auth/totp/verify
    • Get auth_token
  11. Confirm Logged In

    • Endpoint: /auth/me
    • Verify user data returned
  12. Test Backup Code (new login)

    • Logout
    • Login with email/password
    • Use backup code instead of TOTP
    • Endpoint: /auth/totp/verify with is_backup_code: true
  13. Check Backup Codes Remaining

    • Should be 9 (one consumed)
  14. Regenerate Backup Codes

    • Endpoint: /auth/totp/regenerate-backup-codes
    • Provide password
    • Get new set of 10 codes

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

  1. Login without TOTP works when disabled
  2. Enrollment generates secret, QR code, backup codes
  3. Enrollment verification accepts valid TOTP code
  4. TOTP status shows enabled after verification
  5. Login requires TOTP when enabled
  6. TOTP verification works during login
  7. Backup code works for authentication
  8. Backup codes decrement when used
  9. Backup code regeneration works
  10. TOTP disable works with correct password
  11. 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:

  1. All 14 steps complete without errors
  2. All assertions pass
  3. Test can run multiple times (idempotent)
  4. Works from both initial states (TOTP enabled/disabled)

Please review this proposal. Once approved, I'll implement it.