13 KiB
Critical Review: User Authentication Process Concept
Issues Found
1. CRITICAL: Data Model Inconsistency
Location: Line 277 in concept document
Issue: resetTokenExpires is shown as Optional[str] but should be Optional[float]
# WRONG (line 277):
resetTokenExpires: Optional[str] = Field(None, description="Reset token expiration (ISO datetime)")
# CORRECT:
resetTokenExpires: Optional[float] = Field(None, description="Reset token expiration (UTC timestamp in seconds)")
Impact: Implementation confusion, type errors
2. CRITICAL: Config Value Inconsistency
Location: Line 429 in concept document
Issue: Config shows 48 hours but requirement is 24 hours
# WRONG (line 429):
Auth_RESET_TOKEN_EXPIRY_HOURS = 48
# CORRECT:
Auth_RESET_TOKEN_EXPIRY_HOURS = 24
Impact: Wrong expiration time in implementation
3. SECURITY: Missing Rate Limiting
Issue: Password reset request endpoint needs stricter rate limiting than registration
Current: Registration has @limiter.limit("10/minute")
Needed: Password reset request should have stricter limits to prevent:
- Email enumeration attacks
- Spam/DoS attacks
- Brute force attempts
Recommendation:
- Password reset request:
@limiter.limit("5/minute")or@limiter.limit("3/minute") - Password reset (token usage):
@limiter.limit("10/minute")(less critical, token is single-use)
4. SECURITY: Token Invalidation Strategy ✅ CLARIFIED
Issue: What happens when user requests password reset multiple times? Current: Concept doesn't specify behavior Clarification:
- Token is stored in the
UserInDBrecord (single field:resetToken) - When new reset token is generated, old token is overwritten in the database
- No risk: Only one token can exist per user at any time (the last one generated)
- The old token is automatically invalidated because it no longer exists in the database
Status: ✅ No risk - token overwriting ensures only one valid token exists
5. SECURITY: Token Reuse Prevention ✅ CLARIFIED
Issue: What prevents token from being used multiple times? Current: Concept says "Tokens are single-use (cleared after password reset)" but doesn't specify validation Clarification:
- Token is cleared immediately after successful password reset (atomic operation)
- Once cleared, token no longer exists in database
- No risk: If token is used again, validation will fail because token doesn't exist
- Token reuse is prevented by the fact that token is removed from database after use
Status: ✅ No risk - token clearing after use prevents reuse automatically
6. SECURITY: Email Case Sensitivity
Issue: Email uniqueness check - are emails case-sensitive? Current: Concept doesn't specify Risk:
User@Example.comanduser@example.comcould be treated as different- Email enumeration could reveal accounts
Recommendation:
- Normalize emails to lowercase before storage and comparison
- Use
email.lower().strip()in all email operations - Document this in the concept
7. SECURITY: Email Enumeration Prevention ✅ APPROACH SELECTED
Issue: Registration endpoint reveals if email exists Current: Registration rejects if email exists → reveals email is registered Risk: Attacker can enumerate registered emails
Selected Approach:
- ✅ If email exists for LOCAL auth user: Send password reset email to existing user, don't create duplicate account
- ✅ Return generic success message: "Registration successful. Please check your email to set your password."
- ✅ Don't reveal: Whether email already existed or new account was created
- This prevents email enumeration while providing good UX
Status: ✅ Approach selected - send reset email to existing user if email exists
8. EDGE CASE: Multiple Reset Requests ✅ CLARIFIED
Issue: User requests reset multiple times before using first token Current: Concept doesn't specify behavior Clarification:
- Token is stored in
UserInDBrecord (single field) - Only one token can exist at a time - the last one generated
- When new reset request comes in, old token is overwritten in database
- Only the last token is valid - previous tokens are automatically invalidated
- No special handling needed - database structure ensures single token
Status: ✅ No risk - database structure prevents multiple tokens
9. EDGE CASE: User State Changes During Reset
Issue: What happens if user state changes while reset token is active? Scenarios:
- User is disabled (
enabled=False) while reset token is active - User changes email while reset token is active
- User account is deleted while reset token is active
- User sets password via admin while reset token is active
Recommendation:
- On password reset, check user still exists and is enabled
- If user is disabled, allow reset but keep
enabled=False(admin must activate) - If email changed, token should still work (token is tied to user, not email)
- If user deleted, token validation should fail (user not found)
10. EDGE CASE: Expired Token Cleanup ✅ APPROACH SELECTED
Issue: Expired tokens remain in database indefinitely Current: Concept doesn't mention cleanup Risk: Database bloat, potential security issues
Selected Approach:
- ✅ Check token expiration during user authentication (on each login attempt)
- ✅ Clear expired token if found during authentication check
- ✅ Also check during token validation (password reset endpoint) and clear if expired
- ✅ Simplest approach: No separate cleanup job needed, tokens cleaned on access
- This ensures expired tokens are cleaned automatically without additional jobs
Status: ✅ Approach selected - check and clean expired tokens during auth/validation
11. IMPLEMENTATION: Cross-Mandate Search
Issue: How exactly to search across all mandates? Current: Concept says "use root interface" but doesn't specify implementation Questions:
- Does
getRecordsetWithRBACwork with root interface? - Should we bypass RBAC for this search?
- How to ensure we search ALL mandates?
Recommendation:
- Use root interface with
mandateId=Noneor empty filter - Use direct database query if RBAC filtering interferes
- Document exact implementation approach
12. IMPLEMENTATION: Email Search Method
Issue: No existing method to find user by email across mandates
Current: Concept mentions findUserByEmailLocalAuth() but doesn't specify how it works
Questions:
- Does database support case-insensitive email search?
- Should we use exact match or LIKE?
- How to handle NULL emails?
Recommendation:
- Implement method that:
- Uses root interface
- Searches with
recordFilter={"email": email.lower(), "authenticationAuthority": AuthAuthority.LOCAL} - Returns first match or None
- Handles NULL emails gracefully
13. USER EXPERIENCE: Email Delivery Failure ✅ MESSAGE TO ADD
Issue: What if user never receives email? Current: Concept doesn't address this Scenarios:
- Email goes to spam
- Email server is down
- User enters wrong email
- Email delivery is delayed
Selected Approach:
- ✅ Show message about spam folder: "If you don't receive an email within 5 minutes, please check your spam folder"
- ✅ Display this message after registration and password reset request
- Future enhancement: Consider "Resend email" functionality (with rate limiting)
Status: ✅ Message to add - show spam folder reminder
14. USER EXPERIENCE: Password Reset After Registration ✅ NO SPECIAL HANDLING
Issue: User registers, sets password, then immediately forgets it Current: User must use password reset flow Decision:
- ✅ No special handling required - use standard password reset flow
- ✅ User can request password reset like any other user
- ✅ Same token expiration (24 hours) applies to all reset tokens
Status: ✅ No special handling needed
15. MISSING: Token Validation Order
Issue: Order of validation checks not specified Current: Concept lists validations but not order Risk: Inefficient validation, potential security issues
Recommendation:
- Validate in this order:
- Token format (UUID format check)
- Token exists in database
- User exists and is not deleted
- Token matches user's resetToken
- Token not expired (compare timestamps)
- Password strength
- Set password and clear token (atomic operation)
16. MISSING: Atomic Operations ✅ CONFIRMED
Issue: Password reset involves multiple database operations Current: Concept doesn't specify transaction handling Risk:
- Partial updates if operation fails
- Token cleared but password not set
- Race conditions
Confirmation:
- ✅ Use database transaction for password reset operation
- ✅ Atomic operation ensures all-or-nothing:
- Setting passwordHash
- Clearing resetToken and resetTokenExpires
- Setting enabled=True
- ✅ All operations succeed or all fail together
Status: ✅ Confirmed - atomic operations required
17. MISSING: Audit Logging
Issue: No mention of audit logging for security events Current: Concept doesn't specify logging Risk: No audit trail for security incidents
Recommendation:
- Log all password reset requests (with email hash for privacy)
- Log successful password resets
- Log failed token validations
- Log token generation events
18. MISSING: Error Messages
Issue: Error messages could reveal too much information Current: Some error messages are specified, but not all Risk: Information leakage
Recommendation:
- Use generic error messages:
- "Invalid or expired reset token" (don't specify which)
- "Registration failed" (don't specify why)
- "Password reset request processed" (always same message)
- Log detailed errors server-side only
19. MISSING: Frontend Token Validation
Issue: Frontend should validate token format before API call Current: Concept doesn't specify frontend validation Risk: Unnecessary API calls, poor UX
Recommendation:
- Validate UUID format in frontend before calling API
- Show error immediately if token format is invalid
- Extract token from URL and validate on page load
20. MISSING: Magic Link Base URL ✅ LOCATION SPECIFIED
Issue: Magic link generation needs frontend base URL Current: Concept mentions "Should use frontend base URL from config" but doesn't specify Selected Approach:
- ✅ Add frontend URL to frontend env files:
frontend_agents/public/config/env_*.env - ✅ Files to update:
env_int.env- Integration environment URLenv_prod.env- Production environment URL- (Add
env_dev.envif exists)
- ✅ Variable name:
APP_FRONTEND_URLorFrontend_BASE_URL - ✅ Usage: Backend reads from frontend config or gets from request origin
- ✅ Environment-specific: Each env file has its own URL
Status: ✅ Location specified - add to frontend env files
Recommendations Summary
High Priority (Security & Correctness)
- ✅ Fix data model inconsistency (resetTokenExpires type)
- ✅ Fix config value (24 hours, not 48)
- ✅ Add rate limiting to password reset endpoints
- ✅ Implement token invalidation on new reset request
- ✅ Normalize emails to lowercase
- ✅ Prevent token reuse (clear immediately after use)
- ✅ Add atomic transaction for password reset
Medium Priority (Edge Cases)
- ✅ Handle user state changes during reset
- ✅ Implement expired token cleanup
- ✅ Add email delivery failure handling
- ✅ Specify cross-mandate search implementation
- ✅ Add audit logging
Low Priority (UX & Polish)
- ✅ Add frontend token validation
- ✅ Specify magic link base URL configuration
- ✅ Improve error messages (generic, secure)
- ✅ Add resend email functionality (future enhancement)
Security Checklist
- Rate limiting on all endpoints
- Token invalidation strategy implemented
- Token reuse prevention
- Email normalization (lowercase)
- Email enumeration prevention
- Atomic database operations
- Audit logging
- Generic error messages
- Token expiration validation
- User state validation during reset
- Cross-mandate search security (RBAC bypass only for root operations)
Testing Checklist (Additional)
- Multiple reset requests (old token invalidated)
- Token reuse attempt (should fail)
- Expired token usage (should fail)
- User disabled during reset (should handle gracefully)
- Email case variations (User@Example.com vs user@example.com)
- Concurrent reset requests (race condition handling)
- Email delivery failure scenarios
- Invalid token format handling
- Cross-mandate email search accuracy
- Atomic operation rollback on failure