AI Coding Rules for Auth and Security
AGENTS.md rules for authentication and security that prevent agents from rolling custom crypto, leaking secrets, or bypassing authorization checks.
CursorClaude CodeCodexWindsurf Next.jsTypeScriptPostgreSQL
Drop this in your repo root as AGENTS.md. Security rules must be strict — agents are highly capable of writing code that is functionally correct but introduces critical authentication or authorization vulnerabilities.
AGENTS.md
# Project Rules — Auth and Security
## Authentication — hard rules- NEVER implement custom password hashing. Use `bcrypt`, `argon2`, or the auth library's built-in hashing (Better Auth, Auth.js, Clerk, Supabase Auth). Custom hashing is almost always wrong and may be cryptographically broken.- NEVER store plaintext passwords, plaintext tokens, or plaintext secrets in the database. Hash passwords; hash or encrypt tokens before persistence.- NEVER roll custom JWT signing or verification. Use a well-audited library (`jose`, `jsonwebtoken`). Never use `alg: "none"` — reject tokens with no algorithm.- Session tokens must be at least 128 bits of cryptographic randomness. Use `crypto.getRandomValues()` (Web) or `crypto.randomBytes(32)` (Node.js). Do NOT use `Math.random()` for any security-relevant value.- NEVER store session tokens or JWTs in `localStorage`. Use `HttpOnly`, `Secure`, `SameSite=Lax` cookies. `localStorage` is readable by any XSS payload on the page.
## Authorization — hard rules- Every API route and server action MUST check the current user's session before accessing data. Do not assume that reaching a route implies authorization.- Authorization checks must verify ownership or role, not just authentication. "Is logged in" is authentication. "Is allowed to read this resource" is authorization. Both are required.- Never pass a user-controlled ID directly into a database query without first verifying that the authenticated user has permission to access that record. This is an IDOR (Insecure Direct Object Reference) vulnerability.- In Next.js App Router: run auth checks in middleware OR at the top of every Server Component and Server Action that touches user data. Do not rely on client-side redirects for access control.
## Secrets management- All secrets (API keys, database URLs, OAuth client secrets) live in environment variables. Validate them with Zod at startup via `src/lib/env.ts`.- NEVER commit secrets to the repository. If a secret is accidentally committed, treat it as compromised immediately — rotate it before doing anything else.- NEVER log secrets, tokens, or full request bodies that may contain credentials. Scrub sensitive fields before logging.- Client-side code must never contain secrets. In Next.js, only variables prefixed with `NEXT_PUBLIC_` are exposed to the client — and only non-sensitive values should use that prefix.
## Input validation and output encoding- Validate all user input at the server boundary with Zod before use. Never trust client-provided data, including data in headers, cookies, or URL parameters.- Sanitize any HTML rendered from user input. Use a library (`DOMPurify`, `sanitize-html`) — do NOT write a custom HTML sanitizer.- When constructing URLs from user input, use the `URL` constructor to parse and validate. Never concatenate user input into a URL string that will be fetched server-side — this is an SSRF vector.
## CSRF and clickjacking- All state-mutating endpoints (POST, PUT, PATCH, DELETE) must be protected against CSRF. In Next.js App Router, Server Actions are CSRF-protected by default; do not disable this. For custom API routes, verify the `Origin` header or use a CSRF token.- Add `X-Frame-Options: DENY` or `Content-Security-Policy: frame-ancestors 'none'` to pages that should not be embedded in iframes.
## Definition of done- No `Math.random()` calls in authentication or token generation paths.- No `localStorage` for session/token storage (grep the codebase).- Every API route handler has an auth check at the top.- `NEXT_PUBLIC_` env vars contain no secrets (audit the list before shipping).- Zod validation runs on all form inputs before they touch the database.Why these rules
- No
localStoragefor tokens eliminates the most widespread security mistake in React/Next.js applications. Agents that copy authentication patterns from older tutorials (pre-2020) frequently store JWTs inlocalStorage, which is trivially readable by any third-party script on the page.HttpOnlycookies are not accessible from JavaScript at all — they are the correct storage mechanism. - Authorization checks verify ownership, not just authentication closes the IDOR vulnerability that agents most commonly miss. An agent asked to “add an endpoint to fetch a user’s order” will typically check
if (!session)but notif (order.userId !== session.user.id)— because the second check requires understanding the data model’s ownership semantics, which are project-specific and not implied by the task description.
Good fit
- Any application with user accounts, protected resources, or payment data — essentially any production web application.
Not a fit
- Internal tools behind a corporate VPN or network-level access control, where the threat model is different and some of these controls may be handled by the infrastructure layer.