Auth Route Protection Checker
To audit and enhance authentication protection across Next.js routes, server components, and API routes, follow these steps systematically.
Step 1: Discover Project Structure
Identify all files that need authentication checks:
Use Glob to find all route files:
-
app/**/page.tsx
-
Page components
-
app/**/route.ts
-
API routes
-
app/**/layout.tsx
-
Layout components
-
lib/actions/**/*.ts
-
Server actions
Read middleware configuration:
-
middleware.ts
-
Current middleware setup
-
next.config.js
-
Route configuration
Identify authentication setup:
-
Search for auth client files (Supabase, NextAuth, Clerk, etc.)
-
Find auth utility functions
Step 2: Analyze Current Protection
For each discovered file, check for existing auth protection:
Check for Authentication Patterns
Use Grep to search for:
- "auth.getUser()"
- "getSession()"
- "currentUser()"
- "requireAuth"
- "redirect.*login"
- "unauthorized"
- "createServerClient"
Identify Protection Gaps
Flag files that:
-
Have no auth checks
-
Are in protected routes but lack verification
-
Accept user input without auth validation
-
Perform privileged operations without role checks
Consult references/protection-patterns.md for common patterns.
Step 3: Categorize Routes by Protection Level
Classify routes into security categories:
Public Routes - No auth required:
-
Landing pages
-
Marketing content
-
Public blog posts
-
Login/signup pages
Authenticated Routes - Login required:
-
User dashboard
-
Profile pages
-
User-specific data
Role-Protected Routes - Specific roles required:
-
Admin panels
-
Moderator tools
-
Premium features
Action-Protected Routes - Specific permissions required:
-
Edit operations
-
Delete operations
-
Admin actions
Step 4: Generate Protection Report
Create a comprehensive audit report:
Route Protection Audit Report
Generated: [timestamp]
Summary
- Total Routes: X
- Protected: Y
- Unprotected: Z
- Needs Review: N
Unprotected Routes
Critical (Requires immediate attention)
- /app/admin/page.tsx - Admin panel with no auth check
- /app/api/users/delete/route.ts - Delete endpoint unprotected
High Priority
- /app/dashboard/page.tsx - User dashboard missing auth
- /app/api/data/route.ts - API route needs auth
Medium Priority
- /app/profile/page.tsx - Profile page needs verification
Low Priority (Review recommended)
- /app/about/page.tsx - Consider if auth needed
Protected Routes
Properly Protected
- /app/(protected)/settings/page.tsx - Has auth check
- /app/api/auth/logout/route.ts - Auth verified
Needs Enhancement
- [~] /app/admin/users/page.tsx - Has auth but no role check
- [~] /app/api/posts/route.ts - Auth exists but no rate limiting
Step 5: Generate Protection Code
For each unprotected route, generate appropriate protection code:
Server Component Protection
// app/protected-page/page.tsx import { createServerClient } from '@/lib/supabase/server' import { redirect } from 'next/navigation'
export default async function ProtectedPage() { const supabase = createServerClient()
const { data: { user }, error } = await supabase.auth.getUser()
if (error || !user) { redirect('/login') }
// Optional: Role check const { data: profile } = await supabase .from('profiles') .select('role') .eq('id', user.id) .single()
if (profile?.role !== 'admin') { redirect('/unauthorized') }
return <div>Protected Content</div> }
API Route Protection
// app/api/protected/route.ts import { createServerClient } from '@/lib/supabase/server' import { NextResponse } from 'next/server'
export async function GET(request: Request) { const supabase = createServerClient()
const { data: { user }, error } = await supabase.auth.getUser()
if (error || !user) { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ) }
// Optional: Role-based access const userRole = user.user_metadata?.role
if (userRole !== 'admin') { return NextResponse.json( { error: 'Forbidden - Admin access required' }, { status: 403 } ) }
// Protected logic here return NextResponse.json({ data: 'protected data' }) }
Server Action Protection
// lib/actions/admin.ts 'use server'
import { createServerClient } from '@/lib/supabase/server' import { revalidatePath } from 'next/cache'
export async function deleteUser(userId: string) { const supabase = createServerClient()
// Auth check const { data: { user }, error } = await supabase.auth.getUser()
if (error || !user) { throw new Error('Unauthorized') }
// Role check const { data: profile } = await supabase .from('profiles') .select('role') .eq('id', user.id) .single()
if (profile?.role !== 'admin') { throw new Error('Forbidden - Admin access required') }
// Permission check (optional) const canDeleteUsers = await checkPermission(user.id, 'users:delete') if (!canDeleteUsers) { throw new Error('Insufficient permissions') }
// Perform action const { error: deleteError } = await supabase .from('users') .delete() .eq('id', userId)
if (deleteError) throw deleteError
revalidatePath('/admin/users') }
Middleware Protection
// middleware.ts import { createServerClient } from '@/lib/supabase/middleware' import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server'
export async function middleware(request: NextRequest) { const response = NextResponse.next() const supabase = createServerClient(request, response)
const { data: { user } } = await supabase.auth.getUser()
// Protected routes const protectedRoutes = ['/dashboard', '/profile', '/settings'] const isProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route) )
if (isProtectedRoute && !user) { return NextResponse.redirect(new URL('/login', request.url)) }
// Admin routes const adminRoutes = ['/admin'] const isAdminRoute = adminRoutes.some(route => request.nextUrl.pathname.startsWith(route) )
if (isAdminRoute) { if (!user) { return NextResponse.redirect(new URL('/login', request.url)) }
const { data: profile } = await supabase
.from('profiles')
.select('role')
.eq('id', user.id)
.single()
if (profile?.role !== 'admin') {
return NextResponse.redirect(new URL('/unauthorized', request.url))
}
}
return response }
export const config = { matcher: [ '/dashboard/:path*', '/profile/:path*', '/settings/:path*', '/admin/:path*', ] }
Step 6: Generate Helper Functions
Create reusable auth utilities using templates from assets/auth-helpers.ts :
// lib/auth/helpers.ts import { createServerClient } from '@/lib/supabase/server' import { redirect } from 'next/navigation'
export async function requireAuth() { const supabase = createServerClient() const { data: { user }, error } = await supabase.auth.getUser()
if (error || !user) { redirect('/login') }
return user }
export async function requireRole(allowedRoles: string[]) { const user = await requireAuth()
const supabase = createServerClient() const { data: profile } = await supabase .from('profiles') .select('role') .eq('id', user.id) .single()
if (!profile || !allowedRoles.includes(profile.role)) { redirect('/unauthorized') }
return { user, role: profile.role } }
export async function checkPermission( userId: string, permission: string ): Promise<boolean> { const supabase = createServerClient()
const { data } = await supabase .from('user_permissions') .select('permission') .eq('user_id', userId) .eq('permission', permission) .single()
return !!data }
Step 7: Create Testing Suite
Generate tests to verify protection works:
Use templates from assets/auth-tests.ts :
// tests/auth-protection.test.ts import { describe, it, expect } from 'vitest' import { GET } from '@/app/api/protected/route'
describe('Route Protection', () => { it('returns 401 for unauthenticated requests', async () => { const request = new Request('http://localhost/api/protected') const response = await GET(request)
expect(response.status).toBe(401)
})
it('returns 403 for unauthorized role', async () => { // Mock auth with non-admin user const response = await GET(mockRequestWithUser({ role: 'user' }))
expect(response.status).toBe(403)
})
it('allows access for admin users', async () => { const response = await GET(mockRequestWithUser({ role: 'admin' }))
expect(response.status).toBe(200)
}) })
Step 8: Generate Documentation
Create documentation for the protection system:
Authentication & Authorization Guide
Overview
This application uses [Auth Provider] for authentication and role-based access control.
Route Protection Levels
Public Routes
- No authentication required
- Accessible to all visitors
- Examples: /, /about, /login
Authenticated Routes
- Requires user login
- No specific role needed
- Examples: /dashboard, /profile
Role-Protected Routes
- Requires specific role(s)
- Examples: /admin (admin role)
Permission-Protected Routes
- Requires specific permissions
- Granular access control
- Examples: /admin/delete-user (users:delete permission)
Implementation Patterns
[Include code examples and usage guidelines]
Step 9: Suggest Improvements
Based on the audit, suggest security enhancements:
-
Middleware Coverage: Routes missing from middleware config
-
Consistent Patterns: Inconsistent auth check implementations
-
Error Handling: Better error messages and redirects
-
Rate Limiting: API routes needing rate limits
-
CSRF Protection: Forms needing CSRF tokens
-
Audit Logging: Privileged actions needing logging
Consult references/security-best-practices.md for recommendations.
Implementation Guidelines
Best Practices
-
Always check auth on server side, never trust client
-
Use middleware for route-based protection
-
Add role/permission checks for sensitive operations
-
Implement proper error handling and redirects
-
Log authentication failures and suspicious activity
-
Use HTTPS in production
-
Implement rate limiting on auth endpoints
Common Patterns
Consult references/protection-patterns.md for:
-
Server component auth checks
-
API route protection
-
Server action security
-
Middleware configuration
-
Role-based access control
-
Permission-based access control
Output Format
Generate files:
reports/ auth-audit-[timestamp].md security/ auth-helpers.ts (if missing) middleware.ts (enhanced version) tests/ auth-protection.test.ts docs/ auth-guide.md
Verification Checklist
Before completing:
-
All routes categorized by protection level
-
Critical unprotected routes identified
-
Protection code generated for gaps
-
Helper functions created/updated
-
Middleware configured correctly
-
Tests cover auth scenarios
-
Documentation updated
Consulting References
Throughout analysis:
-
Consult references/protection-patterns.md for auth patterns
-
Consult references/security-best-practices.md for guidelines
-
Use templates from assets/auth-helpers.ts
-
Use test templates from assets/auth-tests.ts
Completion
When finished:
-
Display audit report summary
-
Highlight critical issues
-
Provide generated protection code
-
List implementation steps
-
Offer to apply fixes or provide guidance