infrastructure.persistence.models.email_verification_token¶
src.infrastructure.persistence.models.email_verification_token
¶
Email verification token database model for authentication.
This module defines the EmailVerificationToken model for email verification.
Security
- token: Random 32-byte hex string (unguessable, 2^256 possibilities)
- expires_at: 24 hours from creation (balance security vs UX)
- used_at: One-time use (marked as used after verification)
Classes¶
EmailVerificationToken
¶
Bases: BaseModel
Email verification token model for user registration.
Stores one-time use tokens sent to users for email verification. Tokens are short-lived (24 hours) and must be marked as used after verification to prevent reuse.
Token Lifecycle
- Created on user registration
- Sent to user's email (via event handler)
- User clicks verification link
- Token validated and marked as used (used_at set)
- User.is_verified set to True
Security Features
- Random 32-byte hex string (unguessable)
- Short-lived (24 hours expiration)
- One-time use (used_at timestamp)
- Automatic cleanup of expired tokens
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 (24 hours from creation) used_at: Timestamp when token was used (nullable, one-time use)
Indexes
- idx_email_verification_user_id: (user_id) for user's tokens
- idx_email_verification_token: (token) for lookup (unique)
- idx_email_verification_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 verification tokens are immutable (only used_at is set once).
Example
Create verification token (via repository)¶
token = EmailVerificationToken( user_id=user_id, token=secrets.token_hex(32), # 64-char hex string expires_at=datetime.now(UTC) + timedelta(hours=24), ) session.add(token) await session.commit()
Query token (verification)¶
result = await session.execute( select(EmailVerificationToken) .where(EmailVerificationToken.token == token_str) .where(EmailVerificationToken.used_at.is_(None)) .where(EmailVerificationToken.expires_at > datetime.now(UTC)) ) token = result.scalar_one_or_none()
Source code in src/infrastructure/persistence/models/email_verification_token.py
20 21 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 | |