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