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_token HttpOnly 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.