Authentication & Authorization
This guide covers the centralized authentication and authorization system used throughout the Volunteer Portal application.
Architecture Overview
Section titled “Architecture Overview”The application uses a two-layer security approach:
- Middleware - Route-level protection at the edge
- Auth Utilities - Component-level conditional rendering
Middleware-Based Route Protection
Section titled “Middleware-Based Route Protection”All routes are protected by Next.js proxy middleware (proxy.ts) with a secure-by-default approach:
- Default: All routes require admin access
- Explicit allowlisting: Public and user routes must be specifically declared
Route Categories
Section titled “Route Categories”Public Routes (No Authentication Required)
Section titled “Public Routes (No Authentication Required)”These routes are accessible to everyone:
/- Home page/login- Login page/register- Registration page/shifts- Public shifts browsing/api/auth/*- NextAuth endpoints
User Routes (Login Required, Volunteer Access)
Section titled “User Routes (Login Required, Volunteer Access)”These routes require authentication but allow volunteer-level access:
/dashboard- User dashboard/profile/*- Profile management/achievements- Achievement tracking/friends- Friends system/api/profile- Profile API/api/achievements- Achievement API/api/friends- Friends API/api/notifications- Notification API
Admin Routes (Admin Role Required)
Section titled “Admin Routes (Admin Role Required)”All other routes default to admin-only access including:
/admin/*- Admin dashboard/api/admin/*- Admin APIs- Any new routes not explicitly allowlisted
Implementation
Section titled “Implementation”Middleware Configuration
Section titled “Middleware Configuration”The proxy middleware (proxy.ts) automatically:
- Checks authentication status using NextAuth tokens
- Validates user roles for protected routes
- Redirects unauthorized users to appropriate pages
- Preserves the intended destination for post-login redirects
Adding New Routes
Section titled “Adding New Routes”For Public Routes:
Add to the public array in proxy.ts:
public: [ "/new-public-route",]For User Routes:
Add to the user array in proxy.ts:
user: [ "/new-user-route",]For Admin Routes: No action needed - defaults to admin access
Component-Level Authentication
Section titled “Component-Level Authentication”Use the auth utilities (auth-utils.ts) for conditional rendering within components:
import { getAuthInfo } from "@/lib/auth-utils"
export default async function MyComponent() { const { isLoggedIn, isAdmin, user } = await getAuthInfo()
return ( <div> {isLoggedIn && <UserContent />} {isAdmin && <AdminContent />} {user && <p>Welcome, {user.name}!</p>} </div> )}Available Auth Helpers
Section titled “Available Auth Helpers”// Get complete auth informationconst { session, user, isLoggedIn, isAdmin } = await getAuthInfo()
// Helper functionsconst loggedIn = await authHelpers.isLoggedIn()const admin = await authHelpers.isAdmin()const currentUser = await authHelpers.getCurrentUser()Page Protection Patterns
Section titled “Page Protection Patterns”Protected Pages
Section titled “Protected Pages”export default async function AdminPage() { // No auth checks needed - middleware handles protection // Page content...}Conditional UI Rendering
Section titled “Conditional UI Rendering”export default async function FlexiblePage() { const { isLoggedIn, isAdmin } = await getAuthInfo()
return ( <div> <h1>Welcome</h1> {isLoggedIn ? ( <UserDashboard /> ) : ( <PublicContent /> )} {isAdmin && <AdminTools />} </div> )}API Route Protection
Section titled “API Route Protection”Automatic Protection
Section titled “Automatic Protection”API routes are automatically protected by middleware based on their path patterns.
Manual Checks (When Needed)
Section titled “Manual Checks (When Needed)”For granular permissions within protected routes:
export async function POST(request: NextRequest) { // Middleware already verified admin access // Additional checks if needed: const { user } = await getAuthInfo()
if (user?.role !== "SUPER_ADMIN") { return NextResponse.json({ error: "Insufficient permissions" }, { status: 403 }) }
// API logic...}Security Benefits
Section titled “Security Benefits”Secure by Default
Section titled “Secure by Default”- ✅ New routes are automatically protected
- ✅ Cannot accidentally expose admin functionality
- ✅ Explicit allowlisting forces conscious security decisions
- ✅ Centralized configuration reduces inconsistencies
Performance Benefits
Section titled “Performance Benefits”- ✅ Authentication happens at middleware level (before page rendering)
- ✅ Reduced redundant auth checks across components
- ✅ Single source of truth for route permissions
Best Practices
Section titled “Best Practices”- Route Security: Always default to most restrictive access level
- Conditional UI: Use auth utilities for showing/hiding content
- API Protection: Leverage middleware protection, add granular checks only when needed
- Testing: Test both authorized and unauthorized access patterns
- Documentation: Update this guide when adding new route categories
Migration Guidelines
Section titled “Migration Guidelines”When updating existing pages:
- Add route to appropriate middleware category if needed
- Use
getAuthInfo()for conditional UI rendering only - Update tests to account for middleware protection