28 lines
2.8 KiB
Markdown
28 lines
2.8 KiB
Markdown
# ADR 0014: Use revocable server-side merchant sessions
|
|
|
|
- Status: Accepted
|
|
- Date: 2026-08-20
|
|
|
|
## Context
|
|
|
|
The merchant dashboard needs simple username/password authentication for the hackathon demo, strict tenant isolation, logout, account disablement, and authenticated SSE reconnect/replay. Browser-stored JWTs would make immediate revocation and logout enforcement more complex and would expose bearer material to frontend-readable storage if implemented carelessly. A server-side session adds a lookup but keeps authorization state under backend control. If the project is accepted, ZarinPal SSO will replace this demo authentication adapter, so identity work must stay small and separable from merchant authorization.
|
|
|
|
## Decision
|
|
|
|
Use cryptographically random opaque session tokens transported only in host-only `Secure`, `HttpOnly`, `SameSite=Lax` cookies. Store only a non-reversible token digest with server-side session state. Never place authentication tokens in local storage, session storage, URLs, or frontend-readable application state.
|
|
|
|
Sessions expire after 12 hours of inactivity and no later than seven days after creation. Logout revokes the current session before clearing the cookie; disabling a merchant user revokes every active session for that user. Every protected HTTP request, SSE connection, and replay request resolves the merchant boundary from the current server-side session.
|
|
|
|
Passwords use Argon2id with unique salts and reviewed parameters. Expected login failures are externally generic. Demo credentials are generated through a one-time administrative workflow, displayed once, and never stored in Git or logs.
|
|
|
|
Demo usernames are stable lowercase `merchant-NNNN`-style identifiers with case-insensitive comparison. Failed logins are throttled by normalized username and source IP, return `429` with `Retry-After`, and never cause permanent account lockout. State-changing authenticated requests require CSRF tokens and strict same-origin evidence. A user may have at most two active sessions; a third successful login revokes the oldest.
|
|
|
|
## Consequences
|
|
|
|
- Logout, disablement, expiry, and incident response can invalidate access immediately.
|
|
- The backend session store is on the protected-request path and must fail closed, be indexed, and have observable latency/availability.
|
|
- SSE reconnect and replay must reauthorize instead of trusting a previous connection or event id.
|
|
- Scaling API instances does not require sticky sessions when they share the approved authoritative session store.
|
|
- Cookie scope, login-throttle thresholds, and the physical session-store contract remain explicit Identity-spec decisions rather than implicit framework defaults.
|
|
- The credential-verification adapter must be replaceable by ZarinPal SSO without moving tenant authorization into the frontend or analytics packages.
|