UNPKG

@wristband/nextjs-auth

Version:

SDK for integrating your Next.js application with Wristband. Handles user authentication, session management, and token management.

158 lines (157 loc) 6.82 kB
import { NextRequest, NextResponse } from 'next/server'; import { AuthMiddlewareConfig, NormalizedMiddlewareConfig, UnauthenticatedPageHandler } from '../types'; /** * Normalizes middleware configuration by applying default values for optional fields. * * @param config - User-provided middleware configuration with nested strategy configs * @returns Normalized configuration with all strategy configs in nested objects and defaults applied * @throws {TypeError} If configuration validation fails * * @example * ```typescript * const normalized = normalizeMiddlewareConfig({ * authStrategies: ['SESSION'], * sessionConfig: { * sessionOptions: { secrets: 'my-secret', enableCsrfProtection: true }, * }, * protectedPages: ['/dashboard'], * }); * // Returns config with sessionConfig and jwtConfig objects, all defaults applied * ``` */ export declare function normalizeMiddlewareConfig(config: AuthMiddlewareConfig): NormalizedMiddlewareConfig; /** * Resolves the onPageUnauthenticated() handler, using the provided config or creating a default handler * that redirects to the login endpoint with a return_url query parameter. * * @param config - Normalized middleware configuration * @param loginUrl - The full login URL from WristbandAuth config * @returns The resolved onPageUnauthenticated handler function * * @example * ```typescript * // With custom handler * const onPageUnauthenticated = resolveOnPageUnauthenticated(config, loginUrl); * return await onPageUnauthenticated(req); * * // Default behavior (no custom handler provided) * // Redirects to: /api/auth/login?return_url=<current_location> * ``` */ export declare function resolveOnPageUnauthenticated(config: NormalizedMiddlewareConfig, loginUrl: string): UnauthenticatedPageHandler; /** * Creates a route matcher function from an array of URL patterns. * * Supports: * - Exact path matches: `/api/users` * - Named parameters: `/api/users/:id` matches `/api/users/123` * - Wildcards: `/dashboard(.*)` matches `/dashboard`, `/dashboard/settings`, etc. * - Regex patterns: Any valid regex pattern * * @param patterns - Array of route patterns to match against * @returns Matcher function that tests if a pathname matches any pattern * * @example * ```typescript * const matcher = createRouteMatcher([ * '/dashboard(.*)', * '/api/users/:id', * '/settings' * ]); * * matcher('/dashboard/profile'); // true * matcher('/api/users/123'); // true * matcher('/settings'); // true * matcher('/home'); // false * ``` */ export declare function createRouteMatcher(patterns: string[]): (pathname: string) => boolean; /** * Determines if a pathname is a protected API route that requires authentication. * * A route is considered protected if: * 1. SESSION strategy is used and it matches the Session Endpoint (`/api/auth/session` by default) * 2. SESSION strategy is used and it matches the Token Endpoint (`/api/auth/token` by default) * 3. It matches any pattern in `config.protectedApis` * * Note: Session and token endpoints are only protected when using the SESSION authentication strategy. * If using only JWT strategy, these endpoints will not be automatically protected. * * @param pathname - The URL pathname to check * @param config - Normalized middleware configuration * @returns True if the route requires authentication * * @example * ```typescript * // With SESSION strategy and no protectedApis configured * isProtectedApi('/api/users', config); // false (not protected by default) * isProtectedApi('/api/auth/login', config); // false * isProtectedApi('/api/auth/session', config); // true (protected when using SESSION strategy) * isProtectedApi('/api/auth/token', config); // true (protected when using SESSION strategy) * * // With JWT strategy only (no SESSION strategy) * isProtectedApi('/api/auth/session', config); // false (not protected without SESSION strategy) * isProtectedApi('/api/auth/token', config); // false (not protected without SESSION strategy) * * // With protectedApis: ['/api/v1/.*'] * isProtectedApi('/api/v1/users', config); // true * ``` */ export declare function isProtectedApi(pathname: string, config: NormalizedMiddlewareConfig): boolean; /** * Determines if a pathname is a protected page route that requires authentication. * * Checks if the pathname matches any pattern defined in `config.protectedPages`. * Unlike API routes, pages typically redirect unauthenticated users rather than * returning 401 status codes. * * @param pathname - The URL pathname to check * @param config - Normalized middleware configuration * @returns True if the page requires authentication * * @example * ```typescript * // With protectedPages: ['/dashboard(.*)', '/settings'] * isProtectedPage('/dashboard', config); // true * isProtectedPage('/dashboard/profile', config); // true * isProtectedPage('/settings', config); // true * isProtectedPage('/home', config); // false * ``` */ export declare function isProtectedPage(request: NextRequest, config: NormalizedMiddlewareConfig): boolean; /** * Validates the CSRF token for API requests to prevent cross-site request forgery attacks. * * Compares the CSRF token stored in the session against the token provided in the * request header. Both must exist and match exactly for validation to pass. * * This should only be used for API routes, as page navigations don't include CSRF headers. * * @param req - The NextRequest object containing headers * @param csrfToken - The CSRF token stored in the session (from session.csrfToken) * @param csrfHeaderName - The header name to check for the token (default: 'X-CSRF-TOKEN') * @returns True if the CSRF token is valid, false otherwise * * @example * ```typescript * // In middleware for protected API routes * const isValid = isValidCsrf(req, session.csrfToken, 'X-CSRF-TOKEN'); * if (!isValid) { * return new NextResponse(null, { status: 403 }); * } * ``` */ export declare function isValidCsrf(req: NextRequest, csrfToken: string | undefined, csrfHeaderName: string): boolean; /** * Copies all headers from a source Response to a target NextResponse. * This is useful for preserving headers (including Set-Cookie) when creating * new responses in middleware. * * IMPORTANT: Filters out the internal Next.js 'x-middleware-next' header to prevent * routing conflicts when copying headers to error or redirect responses. * * @param source - The source Response to copy headers from * @param target - The target NextResponse to copy headers to * @returns The target NextResponse with headers copied */ export declare function copyResponseHeaders(source: Response, target: NextResponse): NextResponse;