# Pathrule Pattern: Auth (Sessions, JWT, OAuth) (1.0.0)
# ::pathrule:package:auth-sessions-jwt-oauth

### [RULE] Never store auth tokens in localStorage  (path: /src/auth)
<!-- scope: project | priority: medium | advisory -->

Any token that authenticates a request must be set as an httpOnly cookie so JavaScript cannot read it and XSS cannot exfiltrate it.

- Set the session or refresh cookie with `httpOnly`, `secure`, `sameSite: 'lax'` (or `strict` for high-value actions), and the `__Host-` name prefix.
- Never write access tokens, refresh tokens, or session ids to `localStorage`, `sessionStorage`, or non-httpOnly cookies.
- Keep access tokens short lived (15 to 60 minutes) and refresh tokens long lived (7 to 14 days) so a stolen access token expires fast.
- If a short-lived access token must reach the browser for API calls, hold it in memory only, never in persistent storage.

---

### [RULE] Hash passwords with Argon2id, never fast hashes  (path: /src/auth)
<!-- scope: project | priority: medium | advisory -->

Passwords must be hashed with a memory-hard algorithm so offline cracking stays expensive.

- Default to Argon2id via the `argon2` package using OWASP 2026 minimums: 19 MiB memory, 2 iterations, parallelism 1, then tune upward to your hardware.
- Use bcrypt at cost factor 12 or higher only when Argon2 is unavailable in the runtime.
- Never use `md5`, `sha1`, `sha256`, or any unsalted or single-round hash for passwords.
- Compare with the library's built-in `verify` so the work factor and salt are read from the stored hash; never roll your own comparison.

---

### [RULE] Protect cookie-based auth from CSRF  (path: /src/middleware)
<!-- scope: folder | priority: high | strict -->

Because the browser sends auth cookies automatically, every state-changing request needs an explicit CSRF defense.

- Set `sameSite: 'lax'` as the baseline and `strict` on sensitive POST/PUT/PATCH/DELETE flows; SameSite alone is not a complete defense.
- Add a double-submit cookie token (for example `csrf-csrf`) validated on every unsafe method; pure stateless JWT-in-header APIs that never use cookies can skip this.
- Verify `Origin` or `Referer` on state-changing requests as defense in depth.
- Treat `GET`, `HEAD`, and `OPTIONS` as safe and never mutate state in them.

---

### [MEMORY] Sessions vs JWT: pick the right model  (path: /src/auth)

Choosing between server-side sessions and JWTs is the first auth decision and the one agents most often get wrong.

- Default to opaque server sessions stored in Redis or Postgres with an httpOnly cookie. They are revocable instantly, carry no payload to leak, and are simplest to reason about.
- Reach for JWTs only when you genuinely need stateless verification across services or edge runtimes, and accept that revocation requires a denylist or very short TTLs.
- A signed JWT cannot be invalidated before expiry, so keep access token TTL low (15 to 60 min) and pair it with a rotating refresh token.
- Do not put secrets or PII in a JWT payload; it is base64, not encrypted, and is readable by anyone holding it.

---

### [MEMORY] OAuth/OIDC and refresh token rotation  (path: /src/auth)

For third-party login and delegated access, follow RFC 9700 (OAuth 2.0 Security BCP) rather than older tutorials.

- Always use the Authorization Code flow with PKCE, even for confidential clients; the implicit and password grants are deprecated. Use `openid-client` or `oauth4webapi` rather than hand-rolling the flow.
- Validate the `state` parameter against CSRF and validate the OIDC `id_token` signature, `iss`, `aud`, and `nonce` before trusting any claim.
- Rotate refresh tokens on every use: issue a new refresh token and invalidate the old one. If a consumed token is replayed, revoke the entire token family.
- Make rotation atomic with a DB transaction or lock so concurrent refreshes cannot mint two valid tokens for one client.

---

### [SKILL] auth-sessions-jwt-oauth-review  (path: /)

---
name: auth-sessions-jwt-oauth-review
description: Use before merging any authentication change covering sessions, JWTs, OAuth/OIDC, password storage, cookies, CSRF, and token rotation. Run every item against the diff.
---

# Auth (Sessions, JWT, OAuth) review

- [ ] Tokens and session ids are stored in httpOnly, secure, SameSite cookies with a `__Host-` prefix, never in localStorage or sessionStorage.
- [ ] Passwords are hashed with Argon2id at OWASP 2026 parameters (19 MiB, 2 iterations, parallelism 1), or bcrypt cost 12+ only as a documented fallback.
- [ ] No fast or unsalted hash (md5, sha1, sha256) is used for passwords anywhere.
- [ ] Session vs JWT choice is justified: opaque server sessions by default, JWT only when stateless verification is required.
- [ ] Access tokens are short lived (15 to 60 min); JWTs carry no secrets or PII in the payload.
- [ ] OAuth uses Authorization Code + PKCE; implicit and password grants are absent.
- [ ] OAuth `state` is validated and the OIDC `id_token` signature, `iss`, `aud`, and `nonce` are verified before trusting claims.
- [ ] Refresh tokens rotate on every use with replay detection that revokes the token family; rotation is atomic.
- [ ] Cookie-based endpoints enforce CSRF protection (SameSite plus double-submit token) on all state-changing methods.
- [ ] Auth failures return generic messages and do not leak whether the user or password was wrong.
