Authentication library for Next.js applications with support for OAuth, email, and credentials authentication
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Middleware functions for protecting routes and implementing authorization logic in Next.js applications. Provides flexible authentication checks and custom authorization patterns at the edge.
Main middleware function with multiple overloads for different usage patterns and authentication requirements.
/**
* Middleware that checks if user is authenticated/authorized
* @param args - Various argument patterns for different use cases
* @returns Middleware function or middleware response
*/
function withAuth(): ReturnType<NextMiddlewareWithAuth>;
function withAuth(req: NextRequestWithAuth): ReturnType<NextMiddlewareWithAuth>;
function withAuth(req: NextRequestWithAuth, event: NextFetchEvent): ReturnType<NextMiddlewareWithAuth>;
function withAuth(req: NextRequestWithAuth, options: NextAuthMiddlewareOptions): ReturnType<NextMiddlewareWithAuth>;
function withAuth(middleware: NextMiddlewareWithAuth): NextMiddlewareWithAuth;
function withAuth(middleware: NextMiddlewareWithAuth, options: NextAuthMiddlewareOptions): NextMiddlewareWithAuth;
function withAuth(options: NextAuthMiddlewareOptions): NextMiddlewareWithAuth;
type NextMiddlewareWithAuth = (
request: NextRequestWithAuth,
event: NextFetchEvent
) => NextMiddlewareResult | Promise<NextMiddlewareResult>;
type NextMiddlewareResult = ReturnType<NextMiddleware> | void;Usage Examples:
// Basic authentication check (middleware.ts)
export { default } from "next-auth/middleware";
export const config = {
matcher: ["/dashboard/:path*", "/profile/:path*"]
};
// Custom middleware with options
import { withAuth } from "next-auth/middleware";
export default withAuth({
pages: {
signIn: "/login",
error: "/auth-error",
},
});
export const config = {
matcher: ["/admin/:path*"]
};
// Advanced authorization logic
import { withAuth } from "next-auth/middleware";
export default withAuth(
function middleware(req) {
// Custom middleware logic after authentication
console.log("Authenticated user:", req.nextauth.token?.email);
// Additional checks based on route
if (req.nextUrl.pathname.startsWith("/admin") &&
req.nextauth.token?.role !== "admin") {
return Response.redirect(new URL("/unauthorized", req.url));
}
},
{
callbacks: {
authorized: ({ token, req }) => {
// Custom authorization logic
if (req.nextUrl.pathname.startsWith("/admin")) {
return token?.role === "admin";
}
return !!token; // Just require authentication for other routes
},
},
}
);
export const config = {
matcher: ["/dashboard/:path*", "/admin/:path*"]
};Configuration options for customizing middleware behavior and authentication checks.
/**
* Configuration options for NextAuth middleware
*/
interface NextAuthMiddlewareOptions {
/** Custom page URLs for authentication flow */
pages?: AuthOptions["pages"];
/** Custom cookie configuration */
cookies?: Partial<Record<keyof Pick<keyof AuthOptions["cookies"], "sessionToken">, Omit<CookieOption, "options">>>;
/** JWT configuration for token decoding */
jwt?: Partial<Pick<JWTOptions, "decode">>;
/** Authorization callback functions */
callbacks?: {
authorized?: AuthorizedCallback;
};
/** Secret for JWT decoding (defaults to NEXTAUTH_SECRET) */
secret?: string;
}
type AuthorizedCallback = (params: {
/** JWT token (null if not authenticated) */
token: JWT | null;
/** Incoming request object */
req: NextRequest;
}) => Awaitable<boolean>;NextRequest extended with authentication information for use in middleware.
/**
* NextRequest extended with NextAuth token information
*/
interface NextRequestWithAuth extends NextRequest {
/** NextAuth authentication data */
nextauth: {
/** JWT token (null if not authenticated) */
token: JWT | null;
};
}Advanced authorization patterns for complex access control requirements.
/**
* Authorization utilities and patterns
*/
interface AuthorizationPatterns {
/** Role-based access control */
checkRole: (token: JWT | null, requiredRole: string) => boolean;
/** Permission-based access control */
checkPermission: (token: JWT | null, permission: string) => boolean;
/** Multi-factor authentication check */
requireMFA: (token: JWT | null) => boolean;
/** Time-based access control */
checkTimeRestriction: (token: JWT | null, allowedHours: number[]) => boolean;
}Usage Examples:
// Role-based middleware
import { withAuth } from "next-auth/middleware";
export default withAuth({
callbacks: {
authorized: ({ token, req }) => {
// Admin routes require admin role
if (req.nextUrl.pathname.startsWith("/admin")) {
return token?.role === "admin";
}
// Manager routes require manager or admin role
if (req.nextUrl.pathname.startsWith("/manager")) {
return ["admin", "manager"].includes(token?.role as string);
}
// Other protected routes just need authentication
return !!token;
},
},
});
// Permission-based middleware
export default withAuth({
callbacks: {
authorized: ({ token, req }) => {
const pathname = req.nextUrl.pathname;
const permissions = token?.permissions as string[] || [];
// Check specific permissions for different routes
if (pathname.startsWith("/users")) {
return permissions.includes("user:read");
}
if (pathname.startsWith("/reports")) {
return permissions.includes("reports:read");
}
return !!token;
},
},
});
// Multi-factor authentication requirement
export default withAuth({
callbacks: {
authorized: ({ token, req }) => {
if (!token) return false;
// Require MFA for sensitive routes
if (req.nextUrl.pathname.startsWith("/settings/security")) {
return token.mfaVerified === true;
}
return true;
},
},
});
// Time-based access control
export default withAuth({
callbacks: {
authorized: ({ token, req }) => {
if (!token) return false;
// Business hours restriction for admin routes
if (req.nextUrl.pathname.startsWith("/admin")) {
const hour = new Date().getHours();
const businessHours = [9, 10, 11, 12, 13, 14, 15, 16, 17]; // 9 AM - 5 PM
return businessHours.includes(hour);
}
return true;
},
},
});Patterns for protecting specific routes or route groups with different requirements.
/**
* Route protection patterns
*/
interface RouteProtectionPatterns {
/** Protect based on URL pattern */
protectByPattern: (pathname: string, patterns: string[]) => boolean;
/** Protect based on HTTP method */
protectByMethod: (method: string, allowedMethods: string[]) => boolean;
/** Protect based on query parameters */
protectByQuery: (searchParams: URLSearchParams, requiredParams: string[]) => boolean;
}Usage Examples:
// Different protection levels by route
import { withAuth } from "next-auth/middleware";
export default withAuth(
function middleware(req) {
const { pathname } = req.nextUrl;
const token = req.nextauth.token;
// Public API endpoints - no authentication required
if (pathname.startsWith("/api/public")) {
return;
}
// Protected API endpoints - authentication required
if (pathname.startsWith("/api/protected")) {
if (!token) {
return Response.redirect(new URL("/api/auth/signin", req.url));
}
}
// Admin API endpoints - admin role required
if (pathname.startsWith("/api/admin")) {
if (token?.role !== "admin") {
return new Response("Forbidden", { status: 403 });
}
}
}
);
// Method-based protection
export default withAuth(
function middleware(req) {
const { method } = req;
const token = req.nextauth.token;
// Only authenticated users can make POST, PUT, DELETE requests
if (["POST", "PUT", "DELETE"].includes(method) && !token) {
return new Response("Authentication required", { status: 401 });
}
// Only admins can make DELETE requests
if (method === "DELETE" && token?.role !== "admin") {
return new Response("Admin access required", { status: 403 });
}
}
);
// Query parameter based protection
export default withAuth(
function middleware(req) {
const { searchParams } = req.nextUrl;
const token = req.nextauth.token;
// Sensitive operations require additional verification
if (searchParams.get("action") === "delete-account") {
if (!token?.emailVerified) {
return Response.redirect(new URL("/verify-email", req.url));
}
}
// Admin operations require admin role
if (searchParams.get("admin") === "true") {
if (token?.role !== "admin") {
return new Response("Admin access required", { status: 403 });
}
}
}
);Custom error handling and redirect patterns for authentication failures.
/**
* Error handling patterns for middleware
*/
interface MiddlewareErrorHandling {
/** Handle authentication failures */
handleAuthError: (error: string, req: NextRequest) => Response;
/** Handle authorization failures */
handleAuthzError: (reason: string, req: NextRequest) => Response;
/** Custom redirect logic */
customRedirect: (destination: string, req: NextRequest) => Response;
}Usage Examples:
// Custom error pages and redirects
import { withAuth } from "next-auth/middleware";
export default withAuth(
function middleware(req) {
// Custom logic here
},
{
pages: {
signIn: "/auth/signin",
error: "/auth/error",
},
callbacks: {
authorized: ({ token, req }) => {
const { pathname } = req.nextUrl;
// Handle different authorization scenarios
if (pathname.startsWith("/admin")) {
if (!token) {
// Will redirect to signIn page
return false;
}
if (token.role !== "admin") {
// Custom unauthorized handling
return false; // This will redirect to signIn, but we can handle it in middleware
}
return true;
}
return !!token;
},
},
}
);
// Advanced error handling
export default withAuth(
function middleware(req) {
const { pathname } = req.nextUrl;
const token = req.nextauth.token;
// Custom error responses
if (pathname.startsWith("/api/")) {
if (!token) {
return new Response(
JSON.stringify({ error: "Authentication required" }),
{
status: 401,
headers: { "Content-Type": "application/json" }
}
);
}
if (pathname.startsWith("/api/admin") && token.role !== "admin") {
return new Response(
JSON.stringify({ error: "Insufficient permissions" }),
{
status: 403,
headers: { "Content-Type": "application/json" }
}
);
}
}
// Custom page redirects
if (pathname.startsWith("/admin") && token?.role !== "admin") {
return Response.redirect(new URL("/unauthorized", req.url));
}
}
);Next.js middleware configuration for route matching and optimization.
/**
* Next.js middleware configuration
*/
interface MiddlewareConfig {
/** Route patterns to match */
matcher: string | string[];
/** Missing routes configuration */
missing?: Array<{
type: "header" | "query" | "cookie";
key: string;
value?: string;
}>;
/** Has routes configuration */
has?: Array<{
type: "header" | "query" | "cookie";
key: string;
value?: string;
}>;
}Usage Examples:
// Comprehensive matcher patterns
export const config = {
matcher: [
// Protect all dashboard routes
"/dashboard/:path*",
// Protect admin routes
"/admin/:path*",
// Protect API routes except public ones
"/api/((?!public|auth).)*",
// Protect specific pages
"/profile",
"/settings/:path*",
]
};
// Conditional matching with has/missing
export const config = {
matcher: "/api/:path*",
has: [
{
type: "header",
key: "authorization",
}
]
};
// Advanced matching patterns
export const config = {
matcher: [
// Match all routes except specific patterns
"/((?!api/auth|api/public|_next/static|_next/image|favicon.ico).*)",
]
};interface NextFetchEvent {
waitUntil: (promise: Promise<any>) => void;
}
type NextMiddleware = (
request: NextRequest,
event: NextFetchEvent
) => NextResponse | Response | null | undefined | void;
interface CookieOption {
name: string;
options: CookieSerializeOptions;
}
interface CookieSerializeOptions {
domain?: string;
expires?: Date;
httpOnly?: boolean;
maxAge?: number;
path?: string;
priority?: "low" | "medium" | "high";
sameSite?: boolean | "lax" | "strict" | "none";
secure?: boolean;
}interface AuthenticationState {
isAuthenticated: boolean;
user: JWT | null;
hasRole: (role: string) => boolean;
hasPermission: (permission: string) => boolean;
}
type AuthorizationResult = boolean | Response | NextResponse;
interface AuthorizationContext {
token: JWT | null;
request: NextRequest;
pathname: string;
method: string;
searchParams: URLSearchParams;
}