auth
Skill4 starsChanged 5 days agoMITView on GitHub
Implements or migrates to NextAuth v4 credentials auth for Next.js App Router apps against an external REST IdP issuing bearer tokens: authorize() with server-side backend calls, session-token plumbing for RTK Query/fetch layers, middleware route guards, 401 retry and sign-out ladder, OTP registration and password-reset flows, social-login token exchange, deterministic post-login redirects. Use for 'nextauth', 'auth migration', 'login not redirecting', 'stuck on login page', 'refresh fixes login', 'protect routes', 'middleware auth', 'session token', 'signIn credentials', '401 handling', 'session outlives backend token', 'jwt sliding session', 'signOut on every 401', 'random sign-outs', 'signed out while browsing', 'sso account switch', 'third-party 401 logs the user out', 'blank protected page after refresh', 'otp login', 'social login', 'new auth integration'. NOT for OAuth-first setups, Auth.js v5, Firebase auth, or non-Next.js apps.
20 other projects use a version of this.
Adopted by
Most recently taken up by
- crbnos/carbontheir own version, first seen Nov 7, 2026
- marcusbelz/di2-starter-kittheir own version, first seen Oct 31, 2026
- jars-demo/jars-skillstheir own version, first seen Oct 25, 2026
- MartinOlivero/saas-buildertheir own version, first seen Oct 13, 2026
- openai/pluginstheir own version, first seen Oct 13, 2026
- build-dezineer/skills-nuxt4-tw-webapptheir own version, first seen Oct 13, 2026
Used with
Projects with it also use ci-cd, error-handling and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
JohnJBorenSkillci-cd
CI/CD pipeline design, GitHub Actions, testing automation, and deployment strategies
Also in 4 projects that use this
MicrosoftSkillerror-handling
统一错误处理系统。在添加 API 端点、修改错误处理、添加前端 API 调用、编写错误相关测试时使用。
Also in 5 projects that use this
diego-tobalinaSkilllogging
Logging best practices for Java (SLF4J/Logback) and Node.js (Winston/Pino). Use for structured logging, log levels, and avoiding sensitive data exposure.
Also in 3 projects that use this
SentrySkillgithub-issues
Create, update, comment on, label, and inspect GitHub issues with concise, evidence-backed content. Use when users ask to open, edit, view, close, reopen, or triage GitHub issues — including tracking bugs, features, or tasks. Prefer this skill over generic repository tools for issue operations; do not use for pull requests, branches, pushes, or PR creation order questions.
Also in 3 projects that use this
wrsmith108Skilldocker
Container-based development for isolated, reproducible environments. Use when running npm commands, installing packages, executing code, or managing project dependencies. Trigger phrases include "npm install", "run the build", "start the server", "install package", or any code execution request.
Also in 3 projects that use this
SentrySkillui-design
Also in 3 projects that use this
Other versions20 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 20
- openai/plugins★ 7.8ksame name
- epicenter-md/epicenter★ 4.8ksame name
- EpicenterHQ/epicenter★ 4.8ksame name
- danielmeppiel/apm★ 4.2ksame name
- microsoft/apm★ 4.2ksame name
- crbnos/carbon★ 2.8ksame name
- vercel/vercel-plugin★ 328same name
- kagenti/kagenti★ 303same name
- kid-sid/claude-spellbook★ 190same name
- YepAPI/skills★ 8same name
10 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository25 other files it gives its agents.
- AGENTS.mdAGENTS.md
- archifySkill
- brainstormingSkill
- browser-toolsSkill
- code-reviewerSkill
- documentation-writerSkill
- fallow-auditSkill
- frontend-designSkill
- github-actionsSkill
- grill-meSkill
- harness-engineerSkill
- impeccableSkill
- linkedinSkill
- map-integrationSkill
- pidocSkill
- playwright-testerSkill
- ponytailSkill
- refactoring-uiSkill
- rust-skillsSkill
- sdk-developmentSkill
- self-learnSkill
- session-auditSkill
- skill-managerSkill
- systematic-debuggingSkill
- web-searchSkill
The file
We split this skill into the rules it gives an agent
5 rules. 0 are common, 3 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 17 edited versions we read keep these.
3
Distinctive
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
- Very specific: line 63
All backend auth calls inside authorize(), server-side.
- Distinctive: line 73
No token in localStorage, ever: Only client-visible token copy = NextAuth session.
- Distinctive: line 80
Every mutating route: authN + explicit permission.
- Very specific: line 87
No secret in client bundle, git history, image layers or logs — keys/webhooks/broker creds/tokens server-side/env only.
- Distinctive: line 88
No unmaintained dep with known CVEs in the prod tree.
“Common” is measured: kept by at least 6 in 10 of the 17 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
auth
NextAuth v4 (next-auth@4.x) credentials architecture for Next.js App Router app, real IdP = external REST backend issuing bearer tokens. Followed end-to-end kills classic bug class: login resolves, loading stops, redirect never fires (or only after manual refresh).
Entry point
- New integration — implementation sequence below, steps 1–5
- Migrating legacy custom auth (localStorage tokens, cookie-presence middleware, post-login side-effect chains) — references/migration.md first, then sequence
Architecture at a glance
Browser Next.js server External backend
─────── ───────────── ────────────────
signIn("credentials",
{redirect:false}) ──► authorize()
POST /login ──────────────────► access_token
GET /profile (Bearer) ───────► user
maps user + accessToken
+ sessionDuration (JWT exp)
sets httpOnly session cookie ◄── one response
await hydrateSessionToken() (GET /api/auth/session)
router.push(callbackUrl |
referrer | "/")File map (every piece exists for a reason; skip none):
| File | Role |
lib/auth/index.ts | public surface — import from @/lib/auth, never deep paths |
lib/auth/options.ts | authOptions: credentials authorize(), social exchange in jwt callback, type augmentation, auth() = getServerSession |
lib/api.ts | server-side backend REST wrappers (loginApi/getProfileApi) used by authorize() |
app/api/auth/[...nextauth]/route.ts | 4-line route handler exporting GET/POST |
lib/auth/session.ts | module-level token holder + hydrateSessionToken() |
components/provider/SessionTokenSync.tsx | useSession → setSessionToken on every session change |
components/provider/AuthProvider.tsx | SessionProvider + SessionTokenSync |
app/layout.tsx | const session = await auth() → <AuthProvider session> (zero round-trip bootstrap) |
lib/auth/routes.ts | protected/auth route lists + helpers |
proxy.ts (or middleware.ts) | getToken() signature check, redirects both directions |
redux/features/api/apiSlice.ts | baseQueryWithAuth: Bearer from getSessionToken(), 401 retry once, then signOut |
components/auth/LoginPageClient.tsx | signIn → hydrate → redirect chain; OTP + register steps for OTP-gated backends |
Implementation sequence (new integration)
- NextAuth setup —
lib/auth/options.ts+ route handler + env (NEXTAUTH_SECRET,NEXTAUTH_URL). references/nextauth-setup.md - Route protection —
lib/auth/routes.ts+proxy.ts. references/route-protection.md - Token plumbing —
lib/auth/session.ts,SessionTokenSync,AuthProvider, base query. references/token-plumbing.md; expiry, guards and identity switch: references/session-boundaries.md - Flows — login client, register auto-signIn, logout helper: references/login-flows.md
- Optional — OTP registration/forgot-password: references/otp-flows.md; Google/Facebook exchange: references/social-login.md
Hard rules (each fixes a real observed bug)
authorize()throwsnew Error(backendMessage)on bad credentials — neverreturn null. WithsignIn({redirect:false})thrown message becomesresult.errorshown to user;null= generic failure.- Class login failures by HTTP status before user sees them. Single catch in
authorize()rethrowing one message collapses throttling, 5xx, network blips, token anomalies into it — valid credentials told "wrong password", every infra incident reported as frontend bug. Wrap backend calls with error type carrying status (ApiError-style), map: 401 → credentials message, 429 → too-many-attempts (wait a minute), else or network failure → service-unavailable. Report non-401 to Sentry/server logs; wrong passwords = expected user noise. - Per-IP throttling invisible in client-side tests. Backends commonly rate-limit login per source IP (Laravel default throttle: 60/min); Next server funnels every user's login through one egress IP → peak traffic intermittently 429s valid logins — Postman/curl from dev machine = different IP, never reproduces. Throttle responses often HTML error pages: detect 429 by status before parsing body.
- All backend auth calls inside
authorize(), server-side. Client-side post-login fetch chains (profile fetch → set-cookie → redirect) = root cause of no-redirect bug. OnesignIn()= one response = one cookie. await hydrateSessionToken()after every successfulsignIn(login, register auto-login, any programmatic sign-in) before any authorized request or redirect.signIn({redirect:false})resolves beforeuseSessioncache updates; stale empty token → anonymous requests → 401 → logout loop.- Redirect = awaited
router.push(callbackUrl)in the component — neverwindow.location.hrefin an API layer, never conditional on profile fetch. SanitizecallbackUrlto same-origin relative path first — query param, user-controllable;router.push("https://evil.com")= open redirect. - Session cookie maxAge = backend token
exp(decode withjose) — always, no fallback.authorize()rejects tokens without usable expiry ('Login token has no expiry'); guessed lifetime (fixed 24h etc.) kills live sessions early or leaves expired ones minted. Customjwt.encodeoverride, not default. Derive it per encode (backendExp - now): next-auth re-encodes on every session read, so a login-time duration slides expiry — and setsession.expiresfrombackendExpso the client sees the same end. references/session-boundaries.md - API guard:
getToken()+ strictbackendExp <= now. The middleware 120s buffer is a navigation fail-safe only — never copied into the API layer. - 401 with no bearer attached = session not hydrated, not dead — do not sign out.
- A proxy for a second service never forwards that service's 401/403 (map to
502+ one generic message from one shared constant); other statuses pass through so the toast keeps the real reason. A third-party auth failure is a third-party problem: toast it and alert ops — neversignOut, never a permission error on the app account. - SSO landing: a valid blob applies even over an active session when that is the business rule, then hard-navigate; one link = one sign-in POST; an identity change in another tab reloads so no data of the previous user survives.
callbackUrlsanitizer: a same-origin check alone passes//hostand/\host; require exactly one leading slash on the resolved pathname.- 401 ladder in base query: retry only if something can rotate the token between attempts (refresh endpoint, session re-fetch). Static module-holder token → retry byte-identical — skip, go straight to
signOut({redirect:false})+location.replace('/login?callbackUrl=...')gated byisProtectedRoute()so public pages don't bounce. Sign-out single-flight: only base-query ladder owns it —signOutfrom per-request listeners = one expired token → N parallel 401s → N sign-outs → users logged out mid-action. - No token in localStorage, ever. Only client-visible token copy = NextAuth session; API layers read via module holder.
- Social logins exchange provider token for backend token inside
jwtcallback — provider token never stored as app token. - Logout revokes backend session server-side, not only local state; session token never attached to cross-origin or scheme-less URL.
Hardening (from the repo review audit)
- AuthN+authZ server-side, never client-only: don't trust a forgeable cookie/local flag; never ship "all permissions" to every user.
- Every mutating route: authN + explicit permission. Every id-addressed read/write: caller owns/can access the record (IDOR).
- Login needs real credentials — no session for a bare id.
- Tokens: least privilege, never in client JS, never on cross-origin/scheme-less URLs, refresh before expiry.
- Cookies:
Secure+HttpOnly+SameSite; no public-key "encryption" in localStorage. - TLS verification never disabled, incl. proxy agents.
- Service worker: never cache authenticated responses across logout; no
skipWaiting+runtime chunk rewrite stranding stale config. - CSP+security headers set; no ids/secrets in access logs; rate-limit; container ports never bypass the proxy.
- No secret in client bundle, git history, image layers or logs — keys/webhooks/broker creds/tokens server-side/env only; check the built bundle after build.
- No unmaintained dep with known CVEs in the prod tree; audit prod deps, not just dev.
Checklist
authorize()throws with backend message; does all backend auth calls- Login failures class-distinct: 401 credentials / 429 throttled / other or network → service-unavailable; non-401 causes captured server-side
hydrateSessionToken()after signIn and register-auto-login; sets token + user holders- Redirect chain:
callbackUrl(same-origin validated) → same-origin referrer (≠ auth page) → default - Route guard uses
getToken()(signature-verified), not cookie presence - Expiry derived per encode from the IdP token;
session.expiresmatches it; no static fallback lifetime - API routes reject past
backendExp; page buffer 120s; buffer absent from the API layer - Second-service proxy maps upstream 401/403 to 502; upstream text never reaches the browser
- 401 without an attached bearer does not sign out
- SSO/account switch: blob scrubbed from history, one sign-in POST, hard navigation, cross-tab reload; rejected blob keeps the session
- Callback param requires exactly one leading slash
- Unauthenticated on protected →
/login?callbackUrl=<path> - Base query: Bearer per request, 401 ladder (retry only with real token rotation), single-flight signOut fallback
- Session user typed from backend profile; components read domain/user fields via one accessor, not ad-hoc
session?.user?.xchains - Layout passes server session into
SessionProvider - OTP flows: plain endpoints, no auth side effects; resend cooldown enforced
- Social: provider token exchanged for backend token before session write
- AuthN+authZ server-side on every mutating route; id-addressed access verifies ownership (IDOR)
- Cookies
Secure+HttpOnly+SameSite; no token in localStorage; TLS verification on (incl. proxy agents) - No secret in client bundle (check built output); CSP/security headers set
- New integration: legacy-free day one. Migration: legacy storage/cookie/route code deleted, not dormant
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.

