Agent skill
authentication
Load PROACTIVELY when task involves user identity, login, or access control. Use when user says "add authentication", "set up login", "add OAuth", "protect these routes", "implement RBAC", or "add sign-up". Covers session management, JWT tokens, OAuth2 flows, password reset, email verification, protected route middleware, role-based access control, and security hardening (CSRF, rate limiting, token rotation).
Install this agent skill to your Project
npx add-skill https://github.com/mgd34msu/goodvibes-plugin/tree/main/plugins/goodvibes/skills/outcome/authentication
Metadata
Additional technical details for this skill
- tags
-
auth login sign-up session jwt oauth middleware rbac
- version
- 1.0.0
- category
- outcome
SKILL.md
Resources
scripts/
auth-checklist.sh
references/
decision-tree.md
Authentication Implementation Workflow
This skill orchestrates complete authentication implementation from discovery through testing. It replaces library-specific skills (clerk, nextauth, lucia, auth0, firebase-auth, supabase-auth, passport) with a unified workflow that adapts to your stack.
When to Use This Skill
Use when implementing:
- User login and sign-up flows
- Session management (cookies, JWT, server-side sessions)
- OAuth integration (Google, GitHub, etc.)
- Protected routes and API endpoints
- Middleware-based authentication
- Role-based access control (RBAC)
- Token refresh mechanisms
- Password reset flows
Prerequisites
Before starting:
- Understand project framework (Next.js, Remix, Express, etc.)
- Have database schema planned (if using database-backed auth)
- Know authentication approach (managed service vs self-hosted)
- Access to environment variable configuration
Workflow Steps
Step 1: Discovery
Use discover to understand existing authentication patterns:
discover:
queries:
- id: existing-auth
type: grep
pattern: "(useAuth|getSession|withAuth|requireAuth|protect|authenticate)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: middleware-files
type: glob
patterns:
- "**/middleware.{ts,js}"
- "**/auth/**/*.{ts,js}"
- "**/_middleware.{ts,js}"
- id: session-handling
type: grep
pattern: "(session|jwt|token|cookie)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: protected-routes
type: grep
pattern: "(protected|private|requireAuth|withAuth)"
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: files_only
What to look for:
- Existing auth hooks, utilities, or middleware
- Session storage mechanism (cookies, localStorage, server-side)
- Protected route patterns
- Auth provider setup (if using third-party)
Decision Point: If auth is already partially implemented, read existing files to understand the pattern before extending it.
Step 2: Detect Stack
Use detect_stack to determine framework and identify auth approach:
detect_stack:
path: "."
Framework Detection:
- Next.js (App Router): Use middleware.ts + Server Actions + cookies
- Next.js (Pages Router): Use getServerSideProps + API routes + NextAuth
- Remix: Use loader/action auth + session cookies
- Express/Fastify: Use middleware + session store
- tRPC: Use context + middleware
- GraphQL: Use context + directives
Consult Decision Tree: Read references/decision-tree.md to choose between managed (Clerk, Auth0), self-hosted (NextAuth, Lucia), or serverless (Supabase Auth) based on framework and requirements.
Step 3: Implementation Planning
Based on framework and decision tree, plan which files to create/modify:
Common Files Needed:
-
Middleware (
middleware.ts,auth.middleware.ts)- Intercept requests
- Verify authentication status
- Redirect unauthenticated users
-
Auth Utilities (
lib/auth.ts,utils/auth.ts)- Session creation/validation
- Token generation/verification
- Password hashing (bcrypt, argon2)
-
Auth API Routes (
/api/auth/login,/api/auth/signup,/api/auth/logout)- Handle authentication requests
- Set session cookies
- Return auth state
-
Protected Route Wrappers (
withAuth,requireAuth)- HOCs or server utilities
- Check auth before rendering
- Redirect or return 401
-
Client Hooks (
useAuth,useSession)- Access current user
- Manage client-side auth state
- Trigger login/logout
Framework-Specific Patterns:
Next.js App Router:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('session')?.value;
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*']
};
Remix:
// app/utils/session.server.ts
import { createCookieSessionStorage } from '@remix-run/node';
const { getSession, commitSession, destroySession } =
createCookieSessionStorage({
cookie: {
name: '__session',
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
secrets: [process.env.SESSION_SECRET],
sameSite: 'lax'
}
});
export { getSession, commitSession, destroySession };
Express:
// middleware/auth.ts
import jwt from 'jsonwebtoken';
import type { Request, Response, NextFunction } from 'express';
export function requireAuth(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace(/^bearer\s+/i, '');
if (!token) {
return res.status(401).json({ error: 'Unauthorized' });
}
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!);
req.user = payload;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
Step 4: Write Configuration and Core Files
Use precision_write in batch mode to create auth infrastructure:
precision_write:
files:
- path: "middleware.ts"
content: |
# Framework-specific middleware (see patterns above)
- path: "lib/auth.ts"
content: |
# Session validation, token generation
- path: "app/api/auth/login/route.ts"
content: |
# Login endpoint implementation
- path: "app/api/auth/signup/route.ts"
content: |
# Sign-up endpoint with validation
- path: "app/api/auth/logout/route.ts"
content: |
# Logout and session cleanup
verbosity: minimal
CRITICAL: No Placeholders
- Implement full validation (zod, yup, etc.)
- Include proper error handling
- Hash passwords with bcrypt/argon2
- Use secure session configuration
- Add CSRF protection where applicable
Step 5: Install Dependencies
Use precision_exec to install required packages:
precision_exec:
commands:
# For JWT-based auth
- cmd: "npm install jsonwebtoken bcryptjs"
- cmd: "npm install -D @types/jsonwebtoken @types/bcryptjs"
# For session-based auth
- cmd: "npm install express-session connect-redis"
- cmd: "npm install -D @types/express-session"
# For managed services
- cmd: "npm install @clerk/nextjs" # Clerk
- cmd: "npm install next-auth" # NextAuth
- cmd: "npm install better-auth" # Better Auth (replaces deprecated Lucia)
verbosity: minimal
Run Database Migrations (if needed):
precision_exec:
commands:
- cmd: "npx prisma migrate dev --name add_user_auth"
timeout_ms: 60000
- cmd: "npx prisma generate"
verbosity: standard
Step 6: Security Verification
Use analysis-engine tools to verify security:
1. Scan for Hardcoded Secrets:
scan_for_secrets:
paths:
- "lib/auth.ts"
- "app/api/auth/**/*.ts"
- "middleware.ts"
Expected Result: Zero secrets found. All API keys, JWT secrets, and credentials must be in .env files.
If secrets found:
- Move to
.envor.env.local - Use
process.env.VAR_NAMEto access - Add to
.gitignoreif not already present
2. Audit Environment Variables:
env_audit:
check_documented: true
Expected Result: All auth-related env vars documented in .env.example or README.
Required Variables (typical):
JWT_SECRETorSESSION_SECRETDATABASE_URL(if using database)- OAuth credentials (
GOOGLE_CLIENT_ID,GITHUB_CLIENT_SECRET, etc.) NEXTAUTH_URLandNEXTAUTH_SECRET(for NextAuth)
3. Validate Implementation:
# Use precision_grep to validate critical security patterns
precision_grep:
queries:
- id: password_hashing
pattern: "bcrypt|argon2|hashPassword"
path: "lib"
glob: "**/*.ts"
- id: httpOnly_cookies
pattern: "httpOnly.*true|httpOnly:\s*true"
path: "."
glob: "**/*.ts"
- id: csrf_protection
pattern: "csrf|CsrfToken|verifyCsrfToken"
path: "."
glob: "**/*.ts"
output:
format: "count_only"
Step 7: Protected Routes Implementation
Create route protection utilities:
Server-Side Protection (Next.js App Router):
// lib/auth.ts
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
export async function requireAuth() {
const cookieStore = await cookies();
const session = cookieStore.get('session')?.value;
if (!session) {
redirect('/login');
}
const user = await validateSession(session);
if (!user) {
redirect('/login');
}
return user;
}
Client-Side Hook (React):
// hooks/useAuth.ts
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
export function useAuth(options?: { redirectTo?: string }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const router = useRouter();
useEffect(() => {
fetch('/api/auth/me')
.then(res => res.ok ? res.json() : null)
.then(data => {
if (!data && options?.redirectTo) {
router.push(options.redirectTo);
} else {
setUser(data);
}
})
.finally(() => setLoading(false));
}, [options?.redirectTo, router]);
return { user, loading };
}
Apply to Routes:
Use precision_edit to add auth checks to existing routes:
precision_edit:
files:
- path: "app/dashboard/page.tsx"
edits:
- find: "export default function DashboardPage()"
replace: |
export default async function DashboardPage() {
const user = await requireAuth();
hints:
near_line: 1
Step 8: Test Implementation
Use suggest_test_cases to generate auth-specific test scenarios:
suggest_test_cases:
file: "lib/auth.ts"
category: "authentication"
Expected Test Cases:
- Valid login with correct credentials
- Login failure with incorrect password
- Sign-up with valid data
- Sign-up with duplicate email
- Protected route redirects unauthenticated users
- Session token refresh
- Logout clears session
- CSRF token validation
- Password reset flow
Run Validation Script:
bash scripts/auth-checklist.sh .
Expected Exit Code: 0 (all checks pass)
Manual Testing Checklist:
- Sign up new user
- Verify password is hashed in database
- Log in with credentials
- Access protected route (should succeed)
- Log out
- Access protected route (should redirect to login)
- Test OAuth flow (if implemented)
- Verify session persists across page reloads
- Test token expiration and refresh
Common Patterns by Framework
Next.js (App Router)
Session Management:
- Use cookies() from 'next/headers'
- Set httpOnly, secure, sameSite cookies
- Validate in middleware.ts and Server Components
Protected Routes:
- Server-side: await requireAuth() in page/layout
- Client-side: useAuth() hook with redirectTo
- API routes: check cookies in route handlers
OAuth:
- Use NextAuth for simplicity
- Or implement manual OAuth flow with redirect URIs
Remix
Session Management:
- Use createCookieSessionStorage
- Validate in loaders
- Commit session in actions
Protected Routes:
- Check session in loader, throw redirect() if unauthenticated
- Use getSession() utility consistently
OAuth:
- Use remix-auth strategies
- Handle callbacks in dedicated routes
Express/Fastify
Session Management:
- Use express-session + Redis store
- Or JWT tokens in Authorization header
Protected Routes:
- Middleware functions: requireAuth, optionalAuth
- Apply to specific routes or globally
OAuth:
- Use passport.js strategies
- Configure serialize/deserialize user
Error Handling
Follow error-recovery protocol for auth failures:
Login Failures
try {
const user = await validateCredentials(email, password);
await createSession(user.id);
return { success: true };
} catch (err) {
if (err instanceof InvalidCredentialsError) {
// Don't leak whether email exists
return { error: 'Invalid email or password' };
}
if (err instanceof UserLockedError) {
return { error: 'Account locked. Contact support.' };
}
throw err; // Unexpected error
}
Session Validation Failures
export async function validateSession(token: string) {
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!);
return await getUserById(payload.userId);
} catch (err) {
if (err instanceof jwt.TokenExpiredError) {
return null; // Let caller handle (refresh or re-login)
}
if (err instanceof jwt.JsonWebTokenError) {
return null; // Invalid token
}
throw err; // Unexpected error
}
}
Database Errors
try {
const user = await db.user.create({
data: { email, passwordHash }
});
} catch (err) {
if (err.code === 'P2002') {
// Prisma unique constraint violation
return { error: 'Email already registered' };
}
throw err;
}
Security Checklist
Before marking implementation complete:
- Passwords hashed with bcrypt (cost 10+) or argon2
- Session tokens are random (crypto.randomBytes) or signed JWT
- Cookies are httpOnly, secure (in prod), sameSite: 'lax' or 'strict'
- CSRF protection enabled (for cookie-based auth)
- Rate limiting on login/signup endpoints
- Input validation on all auth endpoints
- No sensitive data in error messages
- Environment variables documented in .env.example
- No hardcoded secrets in source code
- Session expiration configured (1-7 days typical)
- Logout clears all auth tokens/sessions
- OAuth redirect URIs whitelisted
References
references/decision-tree.md- Managed vs self-hosted vs serverless comparison.goodvibes/memory/patterns.json- Project-specific auth patternsscripts/auth-checklist.sh- Automated validation script
Troubleshooting
"Session not persisting across requests"
Likely Causes:
- Cookie not being set (check response headers)
- httpOnly preventing client-side access (expected)
- sameSite: 'strict' blocking cross-origin (use 'lax')
- Cookie domain mismatch
Fix:
- Check cookie configuration in auth code
- Verify cookies are in response:
precision_exec: { cmd: "curl -v localhost:3000/api/auth/login" } - Ensure middleware reads cookies correctly
"JWT token invalid after server restart"
Likely Causes:
- JWT_SECRET changes between restarts
- Secret not in .env file
- Different secret in different environments
Fix:
- Move JWT_SECRET to .env:
JWT_SECRET=<random-256-bit-hex> - Generate with:
openssl rand -hex 32 - Never commit .env to git
"OAuth callback fails with redirect_uri_mismatch"
Likely Causes:
- Callback URL not whitelisted in OAuth provider dashboard
- http vs https mismatch
- Port number missing
Fix:
- Check OAuth provider settings
- Add callback URL exactly as it appears in error
- For local dev, use http://localhost:3000/api/auth/callback/google (example)
"Protected routes not redirecting"
Likely Causes:
- Middleware not configured correctly
- Matcher pattern doesn't match route
- Session validation failing silently
Fix:
- Check middleware.ts config.matcher
- Add logging to middleware to verify it's running
- Test session validation independently
Next Steps After Implementation
-
Add role-based access control (RBAC):
- Add
rolefield to User model - Create permission checking utilities
- Protect admin routes
- Add
-
Implement password reset:
- Generate reset tokens
- Send email with reset link
- Validate token and update password
-
Add email verification:
- Generate verification tokens on signup
- Send verification email
- Verify token and mark user as verified
-
Set up refresh tokens:
- Issue short-lived access tokens (15 min)
- Issue long-lived refresh tokens (7 days)
- Rotate refresh tokens on use
-
Add audit logging:
- Log all login attempts (success and failure)
- Track IP addresses and user agents
- Monitor for suspicious activity
Summary
This workflow provides:
- Framework-agnostic authentication implementation
- Security-first approach with validation
- Integration with GoodVibes precision tools
- Automated verification via scripts
- Error handling and troubleshooting
Follow each step sequentially, using precision tools for all file operations and validation.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
testing-strategy
Load PROACTIVELY when task involves writing tests, improving coverage, or test infrastructure. Use when user says "add tests", "write unit tests", "set up E2E testing", "improve coverage", or "add mocks". Covers Vitest/Jest unit tests, React Testing Library component tests, Playwright E2E tests, MSW API mocking, test organization and naming, fixture management, coverage targets and thresholds, snapshot testing, and CI integration.
api-design
Load PROACTIVELY when task involves building or modifying API endpoints. Use when user says "build an API", "add an endpoint", "create a REST route", "set up GraphQL", or "add tRPC procedures". Covers route design and file organization, request validation with Zod, response formatting, error handling patterns, middleware composition, authentication guards, rate limiting, pagination, and API documentation generation.
ai-integration
Load PROACTIVELY when task involves AI, LLM, or machine learning features. Use when user says "add AI chat", "implement streaming responses", "build a RAG pipeline", "add embeddings", or "integrate OpenAI". Covers chat interfaces, streaming with Vercel AI SDK, retrieval-augmented generation, vector search, embeddings pipelines, tool/function calling, and provider abstraction for OpenAI, Anthropic, and local models.
payment-integration
Load PROACTIVELY when task involves payments, billing, or subscriptions. Use when user says "add payments", "integrate Stripe", "set up subscriptions", "add a checkout flow", or "handle billing webhooks". Covers Stripe, LemonSqueezy, and Paddle integration, checkout sessions, subscription lifecycle management, webhook verification and handling, customer portal, metered billing, refunds, and PCI compliance considerations.
state-management
Load PROACTIVELY when task involves application state, data fetching, or form handling. Use when user says "manage state", "add data fetching", "set up Zustand", "handle form validation", or "add React Query". Covers server state (TanStack Query with caching, optimistic updates), client state (Zustand stores), form state (React Hook Form with Zod validation), URL state (search params, routing), and choosing between state solutions.
database-layer
Load PROACTIVELY when task involves database design, schemas, or data access. Use when user says "set up the database", "create a schema", "add a migration", "write a query", or "set up Prisma". Covers schema design and normalization, ORM setup (Prisma, Drizzle), migration workflows, connection pooling, query optimization, indexing strategies, seeding, and transaction patterns for PostgreSQL, MySQL, SQLite, and MongoDB.
Didn't find tool you were looking for?