infrastructure.persistence.models.password_reset_token¶
src.infrastructure.persistence.models.password_reset_token
¶
Password reset token database model for authentication.
This module defines the PasswordResetToken model for password reset flow.
Security
- token: Random 32-byte hex string (unguessable)
- expires_at: 15 minutes (very short, security vs UX tradeoff)
- used_at: One-time use (marked as used after password reset)
- ip_address/user_agent: Track who requested reset (security)
Classes¶
PasswordResetToken
¶
Bases: BaseModel
Password reset token model for password recovery.
Stores very short-lived (15 minutes) one-time use tokens for password reset. Tracks IP address and user agent for security monitoring.
Token Lifecycle
- Created when user requests password reset
- Sent to user's email (via event handler)
- User clicks reset link with token
- Token validated and marked as used (used_at set)
- Password updated, all sessions revoked
Security Features
- Random 32-byte hex string (unguessable)
- Very short-lived (15 minutes expiration)
- One-time use (used_at timestamp)
- Tracks requester IP and user agent
- Password reset revokes ALL user sessions
Fields
id: UUID primary key (from BaseModel) created_at: Timestamp when token created (from BaseModel) user_id: Foreign key to users table (cascade delete) token: Random hex string (64 characters, unique, indexed) expires_at: Timestamp when token expires (15 minutes from creation) used_at: Timestamp when token was used (nullable, one-time use) ip_address: IP address of requester (security tracking) user_agent: User agent of requester (security tracking)
Indexes
- idx_password_reset_user_id: (user_id) for user's tokens
- idx_password_reset_token: (token) for lookup (unique)
- idx_password_reset_cleanup: (expires_at, used_at) for cleanup
Foreign Keys
- user_id: References users(id) ON DELETE CASCADE
Note
This model inherits from BaseModel (NOT BaseMutableModel) because reset tokens are immutable (only used_at is set once).
Security Considerations
- 15 minute expiration (short window for security)
- Tracks IP/user agent (detect suspicious requests)
- Always returns 200 OK (no user enumeration)
- Password reset revokes all sessions (security event)
Example
Create reset token (via repository)¶
token = PasswordResetToken( user_id=user_id, token=secrets.token_hex(32), # 64-char hex string expires_at=datetime.now(UTC) + timedelta(minutes=15), ip_address="192.168.1.1", user_agent="Mozilla/5.0...", ) session.add(token) await session.commit()
Query token (password reset)¶
result = await session.execute( select(PasswordResetToken) .where(PasswordResetToken.token == token_str) .where(PasswordResetToken.used_at.is_(None)) .where(PasswordResetToken.expires_at > datetime.now(UTC)) ) token = result.scalar_one_or_none()
Source code in src/infrastructure/persistence/models/password_reset_token.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |