Design
Architecture
The service is structured around application use cases and explicit ports for storage, security, messaging, and unit-of-work boundaries.
Layering
HTTP handlers
-> DTO parsing and response mapping
-> Application services / use cases
-> Repository / security / messaging ports
-> Postgres, JWT, bcrypt, SMTP, UUID providers
Core Components
| Component | Responsibility |
|---|---|
IdentityService |
Owns registration, email verification and resend, and current-user lookup. |
AuthenticationService |
Owns credential authentication, token issuance and rotation, and access-token validation. |
SessionService |
Lists and revokes the authenticated user's sessions. |
PasswordService |
Owns authenticated password changes and the complete password-reset lifecycle. |
AuthApplicationComponent |
Constructs the four application services and exposes them to userver HTTP handlers. |
JwtTokenProvider |
Signs RS256 access and refresh tokens, parses claims, and exposes public JWKS. |
SessionRepository |
Stores refresh-token hashes, token families, expiry, revocation, and replacement links. |
EmailOutboxProcessor |
Claims pending email jobs, sends SMTP messages, and applies retry/dead-letter state. |
Token Model
- Access tokens are RS256 JWTs with short TTL.
- Refresh tokens are RS256 JWTs delivered through the
refresh_tokenHttpOnly Secure cookie. - Only refresh-token HMAC-SHA256 hashes with a server-side pepper are stored in Postgres.
- Refresh rotates into a new session id while preserving the token family id.
- Detected refresh-token reuse revokes the whole token family.
Session Semantics
A session is the persisted server-side state that backs both the access token and refresh token lifecycle. Access-token authentication accepts a valid JWT only when the session exists, is not revoked, and is not expired.
Password Change
PasswordService verifies the current password, validates the new password with the same
policy used at sign-up, updates the password hash, and revokes all active sessions for the
user. The client must sign in again after a successful password change.
Password Reset
PasswordService owns both reset request and confirmation because they
share one token lifecycle and rate-limit policy. Raw reset tokens are sent through the
email outbox, only hashes are stored, and a successful reset revokes all active sessions.
Email Verification
Sign-up stores only a hash of the verification code and writes a pending email job into the outbox in the same transaction. The outbox worker runs on its own task processor, claims jobs with an ownership lease and row locking, sends them through SMTP, retries transient failures, and clears sensitive sent payloads. Resend requests close any previous active verification record for the user before creating and queueing a fresh code, so only the latest active code can be accepted.
Data Ownership
users: identity, password hash, verification flags, soft deletion.devices: client device metadata captured during sign-in.sessions: refresh hashes, expiry, revocation, token family, replacement links.email_verifications: verification code hashes and attempt metadata.email_outbox: durable email delivery queue.