---
id: auth-security
version: "1.0.0"
title: "Authentication & Authorization Security"
description: "JWT, OAuth 2.0 / OIDC, session management, CSRF, password hashing, and MFA enforcement"
category: prevention
severity: critical
applies_to:
  - "when generating login / signup / password-reset flows"
  - "when generating JWT issuance or verification"
  - "when generating OAuth 2.0 / OIDC client or server code"
  - "when wiring session cookies, CSRF tokens, MFA"
languages: ["*"]
token_budget:
  minimal: 1000
  compact: 1300
  full: 2700
rules_path: "rules/"
related_skills: ["api-security", "crypto-misuse", "secret-detection"]
last_updated: "2026-05-13"
sources:
  - "OWASP Authentication Cheat Sheet"
  - "OWASP Session Management Cheat Sheet"
  - "RFC 6749 — OAuth 2.0"
  - "RFC 7519 — JSON Web Token"
  - "RFC 9700 — OAuth 2.0 Security BCP"
  - "NIST SP 800-63B (Authenticator Assurance)"
---

# Authentication & Authorization Security

## Rules (for AI agents)

### ALWAYS
- For JWT verification, pin the expected algorithm (`RS256`, `EdDSA`, or `ES256`)
  and verify `iss`, `aud`, `exp`, `nbf`, and `iat`. Reject `alg=none` and any
  unexpected algorithm.
- For OAuth 2.0 public clients (SPA / mobile / CLI), use the **authorization
  code flow with PKCE** (S256). Never the implicit flow. Never the resource
  owner password credentials grant.
- Cookies for sessions: `Secure; HttpOnly; SameSite=Lax` (or `Strict` for
  sensitive flows). Use the `__Host-` prefix when there's no subdomain sharing.
- Rotate the session identifier on login and on privilege change. Bind the
  session to the user agent only as a soft signal — never as the sole check.
- Hash passwords with argon2id (m=64 MiB, t=3, p=1) and a per-user random salt.
  Bcrypt cost ≥ 12 or scrypt N≥2^17 are acceptable alternatives for legacy
  systems. PBKDF2-SHA256 requires ≥ 600,000 iterations (OWASP 2023 minimum).
- Enforce password length ≥ 12 characters with no composition rules; allow
  Unicode; check candidate passwords against a known-breached list
  (HIBP / pwned-passwords k-anonymity API).
- Implement account lockout *or* rate limiting for password attempts (NIST
  SP 800-63B §5.2.2: at most 100 failures over 30 days).
- Implement CSRF protection for state-changing requests reachable from a
  browser session: synchronizer token, double-submit cookie, or
  `SameSite=Strict` for high-risk endpoints.
- Require MFA / step-up for administrative operations, password changes,
  MFA-device changes, billing changes.
- For OIDC, validate the `nonce` you sent against the `nonce` in the ID token;
  validate the `at_hash` / `c_hash` when present.

### NEVER
- Use `Math.random()` (or any non-CSPRNG) to generate session IDs, reset
  tokens, MFA recovery codes, or API keys.
- Accept JWT `alg=none`; or accept HS256 from a client when the issuer signs
  with RS256 (classic algorithm-confusion attack).
- Compare passwords or token hashes with `==` / `strcmp`; use a constant-time
  comparator.
- Store passwords reversibly (encrypted instead of hashed). Storage must be
  one-way.
- Leak which of username/password was wrong. Return a generic
  "invalid credentials" message.
- Put access tokens, refresh tokens, or session IDs in URL query strings —
  they leak to logs, Referer headers, and browser history.
- Use `localStorage` / `sessionStorage` to hold long-lived refresh tokens.
  Use HttpOnly cookies.
- Trust client-supplied roles / claims at the API layer — re-derive the
  authenticated subject and look up server-side authorization on each request.
- Issue long-lived (>1 hour) access tokens; rely on refresh tokens with
  rotation.
- Use the implicit flow or the password grant.

### KNOWN FALSE POSITIVES
- Service-to-service tokens with long TTLs are sometimes acceptable when stored
  in a secret manager and bound to a specific workload identity.
- Local-development "magic link" auth without password hashing for ephemeral
  dev users is fine if it's gated behind an env flag and disabled in prod.
- Tokens in URL query are tolerable in *one* place — the OAuth authorization
  code return — because the value is short-lived and one-time-use.

## Context (for humans)

Authentication failures show up consistently in OWASP Top 10 (A07:2021 —
Identification and Authentication Failures). The common modes are: weak
password storage, predictable tokens, missing MFA, JWT misconfiguration, and
session fixation. RFC 9700 (OAuth 2.0 Security BCP) and NIST SP 800-63B are
the authoritative references for the recipe.

AI assistants tend to ship "works in dev" auth: HS256 JWTs with hard-coded
secrets, `bcrypt.hash` with default cost 10, no PKCE, tokens in localStorage.
This skill catches each of those.

## References

- `rules/jwt_safe_config.json`
- `rules/oauth_flows.json`
- [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html).
- [RFC 9700 — OAuth 2.0 Security BCP](https://datatracker.ietf.org/doc/html/rfc9700).
- [NIST SP 800-63B](https://pages.nist.gov/800-63-3/sp800-63b.html).
