Design signup and login service
Company: Bridge.Xyz
Role: Software Engineer
Category: System Design
Difficulty: medium
Interview Round: Technical Screen
Design a basic email/password authentication service that supports user **sign-up** and **login**. You may **not** rely on third-party identity providers (no OAuth/OIDC, no social login). Large-scale traffic is **out of scope** — assume a single relational database is enough — but the bar is a clean API design, a sound database schema, and correct, secure handling of credentials and login state.
Your design should cover:
- The main functional requirements for registration and login.
- API endpoints and their request/response shapes.
- Database tables and key fields.
- How passwords are stored securely.
- How login state is managed after a user authenticates.
- Basic input validation and the important failure cases.
```hint Decompose it
This is a CRUD-plus-security problem, not a scaling problem. Split it into five concerns and address each cleanly: (1) the data model, (2) the API surface, (3) password storage, (4) session/login-state management, (5) validation and abuse. The interviewer is grading correctness and security judgment, not throughput.
```
```hint Password storage
Passwords must be **salted and slow-hashed** — never stored in plaintext and never run through a fast general-purpose hash (MD5/SHA-1/SHA-256). Name a memory-hard, deliberately-slow algorithm and explain what the salt and cost parameters buy you.
```
```hint Login state
After login the server hands the client a credential. Be ready to compare the two standard options — an **opaque server-side session token** vs a **signed self-describing token (JWT)** — and justify your pick on *revocation* and *control*, which matter more than per-request latency when scale is out of scope.
```
```hint The subtle failure case
The trickiest correctness detail is **user enumeration**: a login or signup response must not reveal whether an email is registered, and that includes closing the *timing* side channel, not just the response body.
```
### Constraints & Assumptions
- **Scale is out of scope.** A single stateless app server plus one relational database (e.g. Postgres) is acceptable; no sharding, no distributed session store required (mention where they would plug in).
- **No third-party auth.** Email + password only; you own the credential lifecycle.
- Transport is HTTPS; assume TLS terminates in front of the service.
- The security bar still holds: correct password hashing, no user enumeration, and basic brute-force throttling are expected even though scale isn't.
- You may declare features explicitly **out of scope** (email verification, password reset, MFA, account deletion / GDPR flows) as long as you note where each would attach.
### Clarifying Questions to Ask
- Is the client a **browser** (so cookies are viable) or a **native/mobile/service** client (so a bearer token in the body/header is needed) — or both?
- Should signup **auto-log-in** the user (issue a session immediately), or just create the account?
- How important is **anti-enumeration** for this product? It changes the signup response shape (generic "check your inbox" vs an explicit `409`).
- What session **lifetime** is acceptable, and do we need "log out from all devices"? That influences opaque-token vs JWT.
- Are there **password-policy** requirements (minimum length, breached-password checks) we must enforce?
### What a Strong Answer Covers
A strong answer is judged on the depth and correctness of these dimensions, not on covering every advanced feature:
- **Requirements framing** — separates functional needs (register, login, authenticate later requests, log out, reject duplicate email) from the explicitly out-of-scope items, and states the security bar that survives the "ignore scale" instruction.
- **Data model** — a `users` table with a DB-enforced unique email and a `password_hash` column, and some store of login state; sensible normalization of email case; correct reasoning about *why* uniqueness must be enforced in the database, not just the app.
- **API design** — clean, versioned endpoints with concrete request/response bodies and the right status codes (`201`/`200`/`204`/`400`/`401`/`409`/`429`).
- **Secure password storage** — names a slow, salted, memory-hard hash (Argon2id / bcrypt / scrypt), rejects fast hashes, explains per-password salt and tunable cost, and ideally mentions verification timing and an optional pepper.
- **Session management** — a justified choice between opaque server-side tokens and JWTs, with cookie hardening (`HttpOnly`/`Secure`/`SameSite`) or a bearer-token scheme, expiry, and a revocation story.
- **Validation & failure handling** — input validation, the unique-constraint race on concurrent signups, anti-enumeration (uniform `401` + dummy verify to flatten timing), and login rate limiting that throttles rather than permanently locks out.
### Follow-up Questions
- How would your design change if you later needed **"log out from all of my devices"** and a global "force re-login" after a password change?
- Where exactly would **email verification** and **password reset** flows attach to this schema and API, and what new tokens/tables would they need?
- If per-request session lookups became a real bottleneck, what would you change — and what would you give up by switching to JWTs?
- How do you keep the `sessions` table from growing unbounded, and how would you safely **rotate the password pepper** or **raise the Argon2 cost parameters** for existing users?
Quick Answer: This question evaluates understanding of authentication system design, secure password storage practices, API endpoint and request/response modeling, database schema design, and session or token-based login state management.