CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-next-auth

Authentication library for Next.js applications with support for OAuth, email, and credentials authentication

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

middleware-protection.mddocs/

Middleware and Route Protection

Middleware functions for protecting routes and implementing authorization logic in Next.js applications. Provides flexible authentication checks and custom authorization patterns at the edge.

Capabilities

WithAuth Middleware

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*"]
};

Middleware Options

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>;

Extended Request Type

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;
  };
}

Custom Authorization Patterns

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;
    },
  },
});

Conditional Route Protection

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 });
      }
    }
  }
);

Error Handling and Redirects

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));
    }
  }
);

Middleware Configuration

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).*)",
  ]
};

Types

Middleware Types

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;
}

Authentication State Types

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;
}

docs

authentication-providers.md

core-authentication.md

database-integration.md

index.md

jwt-management.md

middleware-protection.md

react-integration.md

server-side-sessions.md

tile.json