docs(adr): add ADR 0010 (CORS restriction) and 0011 (auth rate limiting)
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# Restrict CORS to explicit allowed origins
|
||||
|
||||
* Status: accepted
|
||||
* Date: 2026-04-26
|
||||
|
||||
## Context and Problem Statement
|
||||
|
||||
The API serves an Angular frontend from a different origin. Cross-Origin Resource Sharing (CORS) must be configured to allow the frontend to call the API. The initial configuration used `cors()` with no options, which sets `Access-Control-Allow-Origin: *` and allows any website to make cross-origin requests to the API — including requests carrying a victim's JWT token.
|
||||
|
||||
## Decision Drivers
|
||||
|
||||
* Any malicious website could make authenticated requests to the API on behalf of a logged-in user (CSRF-like attack via CORS misconfiguration).
|
||||
* The list of legitimate frontend origins is finite and known at deployment time.
|
||||
* The `Authorization: Token <jwt>` header is a non-simple header that always triggers a CORS preflight — the server controls which origins receive a valid preflight response.
|
||||
|
||||
## Considered Options
|
||||
|
||||
* Wildcard CORS (`Access-Control-Allow-Origin: *`)
|
||||
* Explicit origin allowlist via environment variable
|
||||
|
||||
## Decision Outcome
|
||||
|
||||
Chosen option: "Explicit origin allowlist", because it limits cross-origin access to known, trusted frontends. Unknown origins receive no CORS headers and are blocked by the browser.
|
||||
|
||||
Allowed origins are read from the `ALLOWED_ORIGINS` environment variable as a comma-separated list. If the variable is not set, all cross-origin requests are rejected (`origin: false`). `credentials: true` is set to allow the `Authorization` header to be sent cross-origin.
|
||||
|
||||
### Positive Consequences
|
||||
|
||||
* Malicious third-party sites cannot make authenticated cross-origin requests on behalf of users.
|
||||
* Adding a new frontend origin (e.g. a mobile web app) requires only an env var change, no code deployment.
|
||||
|
||||
### Negative Consequences
|
||||
|
||||
* `ALLOWED_ORIGINS` must be set correctly in every environment (dev, staging, prod) or the frontend will fail with CORS errors. Incorrect configuration is a common operational mistake.
|
||||
|
||||
## Pros and Cons of the Options
|
||||
|
||||
### Wildcard CORS
|
||||
|
||||
* Good, because no configuration required.
|
||||
* Bad, because allows any origin — malicious sites can make authenticated requests on behalf of logged-in users.
|
||||
* Bad, because incompatible with `credentials: true` per the CORS spec when `Access-Control-Allow-Origin` is `*`.
|
||||
|
||||
### Explicit origin allowlist
|
||||
|
||||
* Good, because only known frontends can make cross-origin requests.
|
||||
* Good, because configurable per environment without code changes.
|
||||
* Bad, because requires correct `ALLOWED_ORIGINS` configuration in each environment.
|
||||
|
||||
## Links
|
||||
|
||||
* Related to [ADR 0004](0004-route-organisation-by-domain.md) — all API routes are under `/api/*`, making CORS the only cross-origin entry point.
|
||||
Reference in New Issue
Block a user