This template targets internet-exposed APIs that handle user authentication. It defends against the most common classes of attack for that shape of service:
- Credential stuffing / brute force — argon2id password hashing (OWASP-recommended), rate limiting on
/auth/loginand/auth/register. - Password storage compromise — argon2id with per-user salts; a database leak yields hashes that are impractical to reverse at scale.
- Session hijacking via stolen refresh tokens — refresh tokens stored as SHA-256 hashes, rotated on every use, with reuse detection that invalidates all outstanding tokens for the user.
- JWT secret leakage — secrets required to be ≥ 32 chars; short secrets refuse to start. Rotate by redeploying with a new value (invalidates all sessions).
- User enumeration —
/auth/loginreturns a generic 401 for both "unknown email" and "wrong password"; a dummy argon2 verify runs when the user doesn't exist to keep timing comparable. - SQL injection — all queries go through SQLx's parameter binding. No string concatenation into SQL anywhere in the codebase.
- Cross-site request forgery — API responses set
X-Content-Type-Options: nosniff,X-Frame-Options: DENY. CORS defaults to empty (no origins allowed). Operators opt in by settingCORS_ALLOWED_ORIGINS. - Cross-site scripting — the API returns JSON only; no HTML rendering attack surface.
- Denial of service — per-IP rate limiting on auth endpoints. Graceful shutdown on SIGTERM with a 30-second drain window. Beyond that, rely on your load balancer and infrastructure provider.
- Information disclosure in errors — 5xx responses never echo internal state or stack traces; the localized message is always stable. The
localefield leaks which locales are supported (acceptable).
- Account takeover via email recovery — no password-reset flow is shipped. Build this in v2.1 with a separate email sender.
- Phishing — out of scope; depends on user behavior and frontend.
- Insider threats — the database user needs write access; no finer-grained access model.
- Physical / network attacks on the host — operator's responsibility.
- Targeted DDoS — rate limiting is per-IP and local; real DDoS mitigation requires a CDN or a purpose-built service.
To report a security issue, please email <security-contact> (replace this before shipping). Do not open a public GitHub issue for security problems.
We aim to acknowledge reports within 72 hours and issue a fix within 14 days for confirmed vulnerabilities.
Before putting this template in production:
-
JWT_SECRETgenerated from a CSPRNG (openssl rand -hex 32). -
CORS_ALLOWED_ORIGINSset to the specific origins that should reach the API. -
DOCS_ENABLED=falseunless Swagger UI is intentionally public. -
MIGRATE_ON_STARTUP=falseon the long-running app; migrations run in a separate job. - Database connection uses TLS (managed providers do this by default).
- TLS terminator (nginx/Caddy/load-balancer) in front; API does not speak TLS directly.
-
cargo auditclean; Dependabot PRs reviewed regularly. - Backup and restore rehearsed at least once.
| Purpose | Algorithm | Source |
|---|---|---|
| Password hashing | argon2id | argon2 crate, defaults |
| JWT signing | HMAC-SHA256 | jsonwebtoken crate |
| Refresh token hashing | SHA-256 | sha2 crate |
| Refresh token generation | OS CSPRNG | rand::rngs::OsRng |
| TLS (database, when enabled) | rustls | sqlx with rustls feature |