This skill should be used when the user requests to audit, check, or generate authentication and authorization protection for Next.js routes, server components, API routes, and server actions. It analyzes existing routes for missing auth checks and generates protection logic based on user roles and permissions. Trigger terms include auth check, route protection, protect routes, secure endpoints, auth middleware, role-based routes, authorization check, api security, server action security, protect pages.
Audits Next.js routes for missing authentication and authorization checks, then generates protection code for server components, API routes, and server actions based on user roles and permissions. Triggers when you request to check, secure, or generate auth protection for routes, endpoints, or server actions.
/plugin marketplace add hopeoverture/worldbuilding-app-skills/plugin install auth-route-protection-checker@worldbuilding-app-skillsThis skill is limited to using the following tools:
references/protection-patterns.mdTo audit and enhance authentication protection across Next.js routes, server components, and API routes, follow these steps systematically.
Identify all files that need authentication checks:
Use Glob to find all route files:
app/**/page.tsx - Page componentsapp/**/route.ts - API routesapp/**/layout.tsx - Layout componentslib/actions/**/*.ts - Server actionsRead middleware configuration:
middleware.ts - Current middleware setupnext.config.js - Route configurationIdentify authentication setup:
For each discovered file, check for existing auth protection:
Use Grep to search for:
- "auth.getUser()"
- "getSession()"
- "currentUser()"
- "requireAuth"
- "redirect.*login"
- "unauthorized"
- "createServerClient"
Flag files that:
Consult references/protection-patterns.md for common patterns.
Classify routes into security categories:
Public Routes - No auth required:
Authenticated Routes - Login required:
Role-Protected Routes - Specific roles required:
Action-Protected Routes - Specific permissions required:
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
- [x] /app/(protected)/settings/page.tsx - Has auth check
- [x] /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
For each unprotected route, generate appropriate protection code:
// 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>
}
// 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' })
}
// 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.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*',
]
}
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
}
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)
})
})
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]
Based on the audit, suggest security enhancements:
Consult references/security-best-practices.md for recommendations.
Consult references/protection-patterns.md for:
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
Before completing:
Throughout analysis:
references/protection-patterns.md for auth patternsreferences/security-best-practices.md for guidelinesassets/auth-helpers.tsassets/auth-tests.tsWhen finished:
Master authentication and authorization patterns including JWT, OAuth2, session management, and RBAC to build secure, scalable access control systems. Use when implementing auth systems, securing APIs, or debugging security issues.