Compile Ready
All low level design problems
Low Level Design/Advanced/Expert Systems

Design an Authentication Service

Signup/login, password hashing, sessions/tokens, and pluggable providers (password, OTP, OAuth).

Advanced 55m interview 19m read Medium frequency Popularity 80
Strategy Factory Method Chain of Responsibility Amazon Microsoft Google Oracle

Problem Statement

Design the object model for an Authentication Service that supports users, credentials, password login, OAuth login, OTP or MFA login, session creation, token validation, and logout.

The core interview challenge is not a full identity provider or OAuth server. It is the low-level design of a secure, extensible login pipeline where every authentication method plugs into the same flow and tokens are issued, stored, validated, and revoked behind a clean boundary.

A strong answer separates credential verification from session issuance, keeps password hashing out of controllers, avoids storing raw tokens, and makes new auth methods additive instead of forcing a risky switch statement through the login path.

Business context

Authentication sits on the hot path of almost every product. A small design mistake can lock out users, leak credentials, or make future auth methods expensive to add.

Interviewers use this problem to test whether you can balance product flexibility with security discipline: password auth needs slow salted hashing, OAuth needs provider proof validation, OTP needs short-lived second factors, and every successful login must produce a token that can be validated without exposing raw secrets at rest.

The design below models the in-memory LLD shape. Production would replace repositories, verifiers, and secret storage with durable and audited integrations, but the boundaries stay the same.

Functional Requirements

  • Register and look up users by username or email.

  • Store password hashes, not plaintext passwords.

  • Verify password credentials using a dedicated hashing and verification component.

  • Support pluggable auth strategies for password, OAuth, and OTP or MFA.

  • Run every login through a consistent pipeline: lookup, account checks, strategy selection, credential verification, and session issuance.

  • Issue opaque session tokens after successful login.

  • Validate tokens and reject expired, revoked, or unknown tokens.

  • Support logout by revoking the active session token.

Non-Functional Requirements

Security first

Passwords are handled as character arrays, hashed with per-password salt, and verified with constant-time hash comparison. Raw bearer tokens are returned once and only token hashes are stored.

Extensibility

Adding WebAuthn, SAML, magic links, or device approval should mean adding an AuthStrategy, not editing the orchestration flow.

Low latency

User lookup, strategy lookup, and token validation are O(1) map operations in the interview model. Password hashing is intentionally CPU-expensive but bounded.

Auditability

The login pipeline has clear stages where production code can emit structured audit events for success, failure reason class, account lock, token issue, and revoke.

Least privilege

The token service owns token hashing, expiry, validation, and revocation. Login orchestration never reaches into session storage directly.

Requirement Clarification

QAre we designing authorization too?

No. This design authenticates identity and issues a session. Role checks, permissions, and policy evaluation belong to an RBAC or authorization service layered after token validation.

QShould OAuth tokens be issued by our service?

No for the base LLD. We verify a provider proof and link it to a known user identity. Issuing OAuth access tokens to third-party clients is a separate authorization-server design.

QDo we need persistent storage?

Use in-memory maps for the interview implementation. Call out where UserRepository, SessionRepository, and external secret stores would replace them in production.

QHow should MFA interact with password login?

The base design treats OTP as a separate strategy to show pluggability. In production, it often becomes a second stage after password success, still using the same pipeline and strategy seam.

QAre tokens JWTs or opaque tokens?

Use opaque tokens here because secure revocation is simpler. JWTs are a valid alternative when stateless validation is required, but revocation and key rotation become first-class concerns.

UML Class Diagram

Rendering diagram…
The service coordinates a chain of login handlers, delegates credential proof to an **AuthStrategy**, and delegates token lifecycle to the singleton **TokenService**.

Sequence Diagram

Rendering diagram…
Every auth method flows through the same stages. Only the strategy changes, while session creation and validation remain centralized.

Entity Identification

User

Represents an account identity and the authentication material linked to it: password hash, OAuth provider identity, MFA secret, and account lock state.

idusernameemailpasswordHashoauthProvideroauthSubjectmfaSecretlocked

Credentials

Immutable login evidence supplied by the client. Static factory methods construct password, OAuth, or OTP credentials while keeping secrets as character arrays.

methodloginIdsecretproviderexternalSubject

AuthStrategy

Strategy interface for credential verification. Password, OAuth, and OTP implementations expose the same authenticate contract.

method()authenticate(credentials, user)

PasswordAuthStrategy

Owns password hashing and verification using salted PBKDF2. It never returns the stored hash and compares derived hashes in constant time.

hashPasswordverifyPasswordauthenticate

Session

Represents an issued login session with a token hash, issued time, expiry time, and revocation flag.

iduserIdtokenHashissuedAtexpiresAtrevoked

TokenService

Singleton boundary for token generation, token hashing, validation, expiry checks, and revocation. It stores token hashes instead of raw bearer tokens.

sessionsByTokenHashissuevalidaterevoke

AuthService

Facade over the login pipeline. It indexes users, registers strategies, runs chain handlers, issues sessions, validates tokens, and logs users out.

usersByLoginstrategiespipelinetokenService

Design Patterns Used

Strategy

AuthStrategy makes password, OAuth, and OTP verification interchangeable. A new method such as WebAuthn adds a class implementing authenticate and registers it by method.

Factory Method

Credentials.password, Credentials.oauth, Credentials.otp, and AuthService.withDefaultStrategies hide construction details and produce valid objects for common login flows.

Chain of Responsibility

The login flow is modeled as handlers for lookup, account status, strategy selection, credential verification, and session issue. Each stage does one job and passes the context forward.

Singleton

TokenService.getInstance provides one process-wide token authority for issuing, validating, and revoking opaque session tokens in the demo design.

Step-by-Step Design

  1. 1Separate identity from proof

    User stores account identity and linked auth material, while Credentials represents one login attempt. This prevents password, OAuth, and OTP data from leaking into unrelated service methods.

    public static Credentials password(String username, char[] password) {
        return new Credentials(Method.PASSWORD, username, password, null, null);
    }
    
    public static Credentials oauth(String email, String provider, String subject, char[] proof) {
        return new Credentials(Method.OAUTH, email, proof, provider, subject);
    }
  2. 2Put auth method variability behind a strategy

    The login pipeline asks a strategy to authenticate a credential against a user. It does not know whether the proof is a password, provider token, or one-time code.

    public interface AuthStrategy {
        Credentials.Method method();
        AuthResult authenticate(Credentials credentials, User user);
    }
  3. 3Hash passwords in the password strategy only

    PasswordAuthStrategy owns salt generation, PBKDF2 derivation, encoded hash format, and constant-time verification. Controllers and services never manipulate password hashes directly.

    public AuthResult authenticate(Credentials credentials, User user) {
        String storedHash = user.getPasswordHash().orElse(null);
        if (storedHash == null) {
            return AuthResult.failure("password not configured");
        }
        return verifyPassword(credentials.copySecret(), storedHash)
            ? AuthResult.success()
            : AuthResult.failure("password rejected");
    }
  4. 4Run login as a chain of small handlers

    Lookup, account status, strategy selection, verification, and session issue are separate chain stages. This makes rate limiting, risk scoring, device checks, and audit events easy to insert.

  5. 5Issue opaque tokens and store only token hashes

    TokenService.issue returns the raw token once, stores its SHA-256 hash with the session, and validates future requests by hashing the presented token. Expiry and revocation stay inside the token boundary.

    String rawToken = randomToken();
    String tokenHash = hashToken(rawToken);
    Session session = new Session(sessionId, userId, tokenHash, now, now.plus(sessionTtl));
    sessionsByTokenHash.put(tokenHash, session);
  6. 6Keep production integrations replaceable

    The in-memory maps demonstrate ownership. In production, swap in repositories, provider SDK adapters, a KMS-backed secret store, and distributed session storage without changing AuthStrategy or AuthService.login.

Complete Java Implementation

Loading…

Explanation of Every Class

User

Immutable account model. It stores normalized login identifiers and optional auth material for password, OAuth, and MFA, plus lock state for account-level checks.

Credentials

Represents one login attempt. Factory methods create password, OAuth, or OTP credentials and keep the secret in a character array that can be cleared after login.

AuthStrategy

The extension seam for auth methods. The interface defines method and authenticate, while nested OAuth and OTP strategies demonstrate provider-proof and one-time-code verification.

PasswordAuthStrategy

Password-specific strategy. It creates salted PBKDF2 hashes, verifies presented passwords, clears copied secrets, and keeps password logic out of AuthService.

Session

Session record tied to a user and a token hash. It knows whether it is valid at an instant and can be revoked without exposing the raw token.

TokenService

Singleton token authority. It generates high-entropy opaque tokens, stores SHA-256 token hashes, validates expiry and revocation, and removes invalid sessions.

AuthService

Orchestrates the login chain. It indexes users and strategies, executes lookup and checks in order, issues sessions, and exposes validate/logout as the service facade.

Dry Run

Sample input

Users: Alice has a password hash, OAuth link google:alice-123, MFA seed 246810. Token TTL is 30 minutes. Actions: password login, token validation, OTP login with wrong code, logout.

StepInputHandler or componentState changeResult
1password credentials for AlicePasswordAuthStrategyNo session yetPBKDF2 verification succeeds
2successful auth resultSessionIssuingHandlerSession S1 stored by token hash H1Raw token T1 returned once
3validate T1 at +5 minutesTokenServiceNo mutationOptional session S1
4OTP credentials with code 111111OtpAuthStrategyNo session createdSecurityException invalid credentials
5logout T1TokenServiceRemove H1 and mark S1 revokedFuture validate T1 returns empty

The important moment is step 2: the raw bearer token leaves the service once, while only H1 is stored. Step 4 proves failed strategies stop before session issuance.

Complexity Analysis

OperationTimeSpaceNote
login user lookupO(1)O(1)Username and email are indexed in a map.
strategy selectionO(1)O(1)Auth method maps directly to one strategy.
password verificationO(I)O(1)I is the configured PBKDF2 iteration count; intentionally slower than a normal hash.
issue tokenO(1)O(1)Generate random bytes, hash the token, and insert one session.
validate tokenO(1)O(1)Hash presented token, map lookup by token hash, expiry and revocation checks.

The only intentionally expensive operation is password verification. That cost is a security feature. Token validation remains constant time in the in-memory model and should stay cheap in production via indexed session storage or signed-token verification.

Extensibility

Add WebAuthn or passkeys

Implement AuthStrategy for WebAuthn, verify the challenge with a WebAuthn adapter, and register it under a new method. The pipeline remains unchanged.

Add risk-based MFA

Insert a risk-score handler before credential verification or a second-factor handler after password success. The chain structure makes this a local addition.

Persist sessions

Replace the in-memory map inside TokenService with a SessionRepository backed by Redis or SQL. Continue storing token hashes, expiry, and revoked state.

Support device sessions

Add device id, IP range, and user-agent metadata to Session and enforce device-level revocation without changing credential strategies.

Use JWTs

Swap opaque-token storage for signed JWT validation inside TokenService. Keep key rotation, short TTLs, and revocation lists behind the same service boundary.

Alternative Designs

JWT-first stateless sessions

Issue signed JWTs with user id, expiry, issuer, and audience. Validation becomes signature verification and claim checks without a session lookup.

Tradeoffs

Great for distributed read-heavy systems, but logout, token theft response, and permission changes need short TTLs, revocation lists, or token versioning.

Two-phase MFA pipeline

After password success, return a pending challenge id instead of a session. A second login call verifies OTP or push approval and then issues the token.

Tradeoffs

Closer to production MFA and better UX control, but adds challenge state, retries, expiry, and more failure modes to explain.

External identity provider adapter

Delegate all credential verification to an IdP such as Okta, Entra ID, or Cognito and keep only local session issuance plus user mapping.

Tradeoffs

Reduces credential risk, but the local service still needs clean token handling, account linking, downtime behavior, and audit boundaries.

Common Mistakes

  • ×

    Storing plaintext passwords or using a fast general hash instead of a slow salted password hash.

  • ×

    Returning different error messages for unknown user and wrong password, which enables user enumeration.

  • ×

    Hard-coding password, OAuth, and OTP branches directly inside AuthService.login instead of using strategies.

  • ×

    Storing raw bearer tokens in memory or a database instead of token hashes.

  • ×

    Issuing a session before all credential checks and account-state checks finish.

  • ×

    Treating OAuth login as only matching an email without verifying the provider proof and linked subject.

  • ×

    Forgetting token revocation, expiry checks, and logout behavior.

Follow-up Interview Questions

QHow would you prevent brute-force password attempts?

Add a rate-limit or risk handler early in the chain, keyed by user id, IP, device, and method. Store counters outside the process and emit audit events for lockout decisions.

QHow do you rotate token signing keys or token hashes?

For opaque tokens, rotate hashing pepper or storage keys with versioned hashes. For JWTs, keep a key id, publish active public keys, and validate old keys until their tokens expire.

QWhere does account lockout belong?

In a chain handler after user lookup and before credential verification. It is account policy, not password strategy logic.

QHow would OAuth account linking be secured?

Store provider plus immutable subject id, not only email. Require proof from the provider adapter and avoid auto-linking by mutable email alone.

QHow do you support logout from all devices?

Store sessions by user id as well as token hash, then revoke every active session for that user. JWT designs need token versioning or a revocation list.

Production Considerations

Secret storage

Keep password hashes, MFA seeds, OAuth client secrets, and token peppers in appropriate stores. MFA seeds and provider secrets should be encrypted with managed keys.

Password policy and migration

Version password hash formats so you can migrate from PBKDF2 to Argon2 or stronger parameters on next successful login without forcing a reset.

Distributed sessions

Use Redis or a database with TTL indexes for opaque sessions. Keep token hash as the lookup key and avoid logging raw tokens.

Observability

Measure login success rate, failure reason classes, password hash latency, token validation latency, lockouts, and suspicious IP or device patterns.

Audit and compliance

Record who logged in, method used, when tokens were issued or revoked, and admin-driven account changes. Keep audit logs append-only and privacy-aware.

Transport security

Require TLS, secure cookies or authorization headers, SameSite protections for browser sessions, CSRF defenses where cookies are used, and strict token redaction in logs.

What Interviewers Look For

  • Did the candidate separate authentication from authorization?

  • Did they use Strategy for password, OAuth, and OTP instead of a brittle switch statement?

  • Did they mention salted slow password hashing and constant-time verification?

  • Did they avoid storing raw tokens and define expiry plus revocation?

  • Did they model the login flow as ordered steps with clear failure boundaries?

  • Can they explain how a new auth method is added without changing existing method logic?

Quiz

0/5 answered

  1. 1.Why should **AuthService.login** not contain all password, OAuth, and OTP checks inline?

  2. 2.What should be stored for an opaque session token?

  3. 3.Which pipeline stage should reject a locked account?

  4. 4.What makes PBKDF2, bcrypt, scrypt, or Argon2 better for passwords than SHA-256 alone?

  5. 5.Why store OAuth provider plus subject id instead of only provider email?

Practice Variants

Add WebAuthn passkey login

Advanced

Create a new AuthStrategy that verifies a WebAuthn assertion using a challenge store and public key. Register it without editing the existing strategies.

Implement two-step MFA

Advanced

Change password success to return a pending challenge, then issue the session only after OTP verification. Keep challenge expiry and retry limits explicit.

Add login rate limiting

Intermediate

Insert a chain handler that checks attempts per user and IP before credential verification. Decide what state must be distributed across app instances.

Flashcards

Cheat Sheet

Entities: User, Credentials, AuthStrategy, PasswordAuthStrategy, Session, TokenService, AuthService.

Patterns: Strategy for auth methods, Factory Method for credential/service creation, Chain of Responsibility for login stages, Singleton for token authority.

Login flow: normalize credentials → lookup user → check account status → select strategy → verify proof → issue token.

Token flow: generate opaque token → hash token → store session by hash → return raw token once → validate by hashing presented token.

Security rules: never store plaintext passwords, never store raw bearer tokens, avoid user enumeration, enforce expiry and revocation, audit every sensitive transition.

Extensibility: add a method by implementing AuthStrategy and registering it; add policy by inserting a chain handler.

References