next-token-auth 1.0.18 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -2
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -7
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +3 -1
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.js +6 -7
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +6 -7
- package/dist/react/index.mjs.map +1 -1
- package/dist/server/index.d.mts +21 -1
- package/dist/server/index.d.ts +21 -1
- package/dist/server/index.js +41 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +41 -1
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/crypto.ts","../../src/utils/expiry.ts","../../src/server/getServerSession.ts","../../src/server/withAuth.ts","../../src/server/middleware.ts","../../src/server/handlers.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Lightweight symmetric encryption using AES-GCM via the Web Crypto API.\n * Works in both browser and Node.js (>=18) / Edge runtimes.\n */\n\nconst ALGO = \"AES-GCM\";\nconst IV_LENGTH = 12; // bytes\n\nfunction getTextEncoder() {\n return new TextEncoder();\n}\n\nfunction getTextDecoder() {\n return new TextDecoder();\n}\n\nasync function deriveKey(secret: string): Promise<CryptoKey> {\n if (!secret) {\n throw new Error(\n \"[next-token-auth] `secret` is undefined. \" +\n \"If using cookie storage, ensure AUTH_SECRET is set in your environment.\"\n );\n }\n const raw = getTextEncoder().encode(secret.padEnd(32, \"0\").slice(0, 32));\n return crypto.subtle.importKey(\"raw\", raw, { name: ALGO }, false, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\n/**\n * Encrypts a plaintext string using AES-GCM.\n * Returns a base64url-encoded string: `<iv>.<ciphertext>`\n */\nexport async function encrypt(data: string, secret: string): Promise<string> {\n const key = await deriveKey(secret);\n const ivArray = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n // Ensure we have a plain ArrayBuffer for SubtleCrypto\n const iv = ivArray.buffer.slice(0, IV_LENGTH) as ArrayBuffer;\n const encoded = getTextEncoder().encode(data);\n\n const cipherBuffer = await crypto.subtle.encrypt({ name: ALGO, iv }, key, encoded);\n\n const ivB64 = bufferToBase64(new Uint8Array(iv));\n const cipherB64 = bufferToBase64(new Uint8Array(cipherBuffer));\n return `${ivB64}.${cipherB64}`;\n}\n\n/**\n * Decrypts a string produced by `encrypt`.\n */\nexport async function decrypt(data: string, secret: string): Promise<string> {\n const [ivB64, cipherB64] = data.split(\".\");\n if (!ivB64 || !cipherB64) {\n throw new Error(\"decrypt: invalid ciphertext format\");\n }\n\n const key = await deriveKey(secret);\n const ivBytes = base64ToBuffer(ivB64);\n const iv = ivBytes.buffer.slice(\n ivBytes.byteOffset,\n ivBytes.byteOffset + ivBytes.byteLength\n ) as ArrayBuffer;\n\n const cipherBytes = base64ToBuffer(cipherB64);\n const cipherBuffer = cipherBytes.buffer.slice(\n cipherBytes.byteOffset,\n cipherBytes.byteOffset + cipherBytes.byteLength\n ) as ArrayBuffer;\n\n const plainBuffer = await crypto.subtle.decrypt({ name: ALGO, iv }, key, cipherBuffer);\n\n return getTextDecoder().decode(plainBuffer);\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction bufferToBase64(buffer: Uint8Array): string {\n return btoa(String.fromCharCode(...buffer))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nfunction base64ToBuffer(b64: string): Uint8Array {\n const padded = b64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded);\n return Uint8Array.from(binary, (c) => c.charCodeAt(0));\n}\n","import type { ExpiryInput, ExpiryStrategy, LoginResponse } from \"../types\";\n\nconst UNIT_MAP: Record<string, number> = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n w: 604800,\n};\n\n/**\n * Parses an expiry value into seconds.\n * Accepts:\n * - number → treated as seconds\n * - string → e.g. \"15m\", \"2h\", \"2d\", \"7d\", \"1w\"\n *\n * @throws if the format is unrecognised\n */\nexport function parseExpiry(input?: ExpiryInput): number {\n if (input === undefined || input === null) {\n throw new Error(\"parseExpiry: no expiry value provided\");\n }\n\n if (typeof input === \"number\") {\n if (input <= 0) throw new Error(\"parseExpiry: value must be positive\");\n return input;\n }\n\n const trimmed = input.trim();\n\n // Pure numeric string\n if (/^\\d+$/.test(trimmed)) {\n return parseInt(trimmed, 10);\n }\n\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*([smhdw])$/i);\n if (!match) {\n throw new Error(\n `parseExpiry: unrecognised format \"${input}\". ` +\n `Expected a number or a string like \"15m\", \"2h\", \"2d\", \"7d\", \"1w\".`\n );\n }\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n return Math.floor(value * UNIT_MAP[unit]);\n}\n\n/**\n * Safely parses an expiry value, returning a fallback on failure.\n */\nexport function safeParseExpiry(\n input?: ExpiryInput,\n fallbackSeconds = 900\n): number {\n try {\n return parseExpiry(input);\n } catch {\n return fallbackSeconds;\n }\n}\n\n/**\n * Resolves the access token expiry timestamp (ms) from a login response\n * using the configured strategy.\n */\nexport function resolveAccessTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number {\n const now = Date.now();\n\n const fromBackend =\n response.accessTokenExpiresIn ?? response.expiresIn ?? undefined;\n\n if (strategy === \"backend\") {\n if (fromBackend === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"backend\" but API returned no expiry'\n );\n }\n return now + parseExpiry(fromBackend) * 1000;\n }\n\n if (strategy === \"config\") {\n if (configExpiry === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"config\" but no expiry configured'\n );\n }\n return now + parseExpiry(configExpiry) * 1000;\n }\n\n // hybrid: backend first, fallback to config\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n // Last resort: 15 minutes\n return now + 900 * 1000;\n}\n\n/**\n * Resolves the refresh token expiry timestamp (ms).\n */\nexport function resolveRefreshTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number | undefined {\n const now = Date.now();\n const fromBackend = response.refreshTokenExpiresIn;\n\n if (strategy === \"backend\") {\n return fromBackend !== undefined\n ? now + parseExpiry(fromBackend) * 1000\n : undefined;\n }\n\n if (strategy === \"config\") {\n return configExpiry !== undefined\n ? now + parseExpiry(configExpiry) * 1000\n : undefined;\n }\n\n // hybrid\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n return undefined;\n}\n","import type { AuthConfig, AuthSession, AuthTokens, LoginResponse } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n cookies: {\n get(name: string): { value: string } | undefined;\n };\n};\n\n/**\n * Retrieves and validates the auth session on the server side.\n * Reads the encrypted session cookie, validates token expiry,\n * and refreshes if needed.\n *\n * Compatible with Next.js App Router (NextRequest) and Pages Router (IncomingMessage).\n *\n * @example\n * // app/dashboard/page.tsx\n * import { getServerSession } from \"next-token-auth/server\";\n *\n * export default async function Page({ request }) {\n * const session = await getServerSession(request, config);\n * if (!session.isAuthenticated) redirect(\"/login\");\n * }\n */\nexport async function getServerSession<User = unknown>(\n req: NextRequest,\n config: AuthConfig<User>\n): Promise<AuthSession<User>> {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = req.cookies.get(cookieName)?.value;\n\n if (!cookieValue) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n let tokens: AuthTokens | null = null;\n\n try {\n const json = await decrypt(cookieValue, config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n const now = Date.now();\n const threshold = (config.refreshThreshold ?? 60) * 1000;\n const accessExpired = now >= tokens.accessTokenExpiresAt - threshold;\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n\n // Both expired → clear session\n if (accessExpired && refreshExpired) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n // Access expired but refresh valid → attempt server-side refresh\n if (accessExpired && !refreshExpired) {\n const refreshed = await serverRefresh<User>(tokens, config);\n if (!refreshed) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n tokens = refreshed;\n }\n\n const user = await fetchUser<User>(tokens.accessToken, config);\n\n return {\n user,\n tokens,\n isAuthenticated: true,\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nasync function serverRefresh<User>(\n tokens: AuthTokens,\n config: AuthConfig<User>\n): Promise<AuthTokens | null> {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const refreshPath = config.endpoints.refresh.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${refreshPath}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as LoginResponse<User>;\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(\n data,\n config.expiry?.accessTokenExpiresIn,\n strategy\n ),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(\n data,\n config.expiry?.refreshTokenExpiresIn,\n strategy\n ),\n };\n } catch {\n return null;\n }\n}\n\nasync function fetchUser<User>(\n accessToken: string,\n config: AuthConfig<User>\n): Promise<User | null> {\n if (!config.endpoints.me) return null;\n\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const mePath = config.endpoints.me.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${mePath}`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!res.ok) return null;\n return (await res.json()) as User;\n } catch {\n return null;\n }\n}\n","import type { AuthConfig, AuthSession } from \"../types\";\nimport { getServerSession } from \"./getServerSession\";\n\ntype NextRequest = {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string };\n};\n\ntype NextResponse = {\n redirect(url: URL): NextResponse;\n next(): NextResponse;\n};\n\ntype RouteHandler<User = unknown> = (\n req: NextRequest,\n session: AuthSession<User>\n) => Promise<Response> | Response;\n\n/**\n * Higher-order function that wraps a Next.js route handler with auth protection.\n * Redirects unauthenticated requests to the login page.\n *\n * @example\n * // app/api/protected/route.ts\n * export const GET = withAuth(config, async (req, session) => {\n * return Response.json({ user: session.user });\n * });\n */\nexport function withAuth<User = unknown>(\n config: AuthConfig<User>,\n handler: RouteHandler<User>,\n options: { redirectTo?: string } = {}\n) {\n return async (req: NextRequest): Promise<Response> => {\n const session = await getServerSession<User>(req, config);\n\n if (!session.isAuthenticated) {\n const redirectTo = options.redirectTo ?? \"/login\";\n const loginUrl = new URL(redirectTo, `https://${req.nextUrl.pathname}`);\n return Response.redirect(loginUrl);\n }\n\n return handler(req, session);\n };\n}\n","import type { AuthConfig } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport type { AuthTokens } from \"../types\";\n\n/**\n * Next.js middleware factory for route protection.\n *\n * @example\n * // middleware.ts (project root)\n * import { authMiddleware } from \"next-token-auth/server\";\n * import { authConfig } from \"./lib/auth\";\n *\n * export const middleware = authMiddleware(authConfig);\n *\n * export const config = {\n * matcher: [\"/auth/login\", \"/auth/register\", \"/dashboard*\", \"/profile*\"],\n * };\n */\nexport function authMiddleware<User = unknown>(authConfig: AuthConfig<User>) {\n return async function middleware(request: {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string; origin: string };\n url: string;\n }): Promise<Response> {\n const { NextResponse } = await import(\"next/server\");\n\n const pathname = request.nextUrl.pathname;\n const cookieName = authConfig.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = request.cookies.get(cookieName)?.value;\n\n const isAuthenticated = await checkSession(cookieValue, authConfig.secret);\n\n // ── Guest-only routes ────────────────────────────────────────────────────\n // Accessible only when NOT authenticated.\n // Authenticated users are redirected to redirectAuthenticatedTo.\n const guestOnlyRoutes = authConfig.routes?.guestOnly ?? [];\n if (isGuestOnlyRoute(pathname, guestOnlyRoutes)) {\n if (isAuthenticated) {\n const redirectTo = authConfig.routes?.redirectAuthenticatedTo ?? \"/dashboard\";\n return NextResponse.redirect(new URL(redirectTo, request.nextUrl.origin));\n }\n return NextResponse.next();\n }\n\n // ── Public routes ────────────────────────────────────────────────────────\n const publicRoutes = authConfig.routes?.public ?? [];\n if (matchesAny(pathname, publicRoutes)) {\n return NextResponse.next();\n }\n\n // ── Protected routes ─────────────────────────────────────────────────────\n const protectedRoutes = authConfig.routes?.protected ?? [];\n const requiresAuth =\n protectedRoutes.length === 0 || matchesAny(pathname, protectedRoutes);\n\n if (!requiresAuth) {\n return NextResponse.next();\n }\n\n if (!isAuthenticated) {\n // Use the configured login endpoint path, falling back to \"/login\"\n const loginPath = authConfig.routes?.loginPath ?? \"/login\";\n return NextResponse.redirect(new URL(loginPath, request.nextUrl.origin));\n }\n\n return NextResponse.next();\n };\n}\n\n// ─── Session check ────────────────────────────────────────────────────────────\n\nasync function checkSession(\n cookieValue: string | undefined,\n secret: string\n): Promise<boolean> {\n if (!cookieValue) return false;\n\n try {\n const json = await decrypt(cookieValue, secret);\n const tokens = JSON.parse(json) as AuthTokens;\n const now = Date.now();\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n return !refreshExpired;\n } catch {\n return false;\n }\n}\n\n// ─── Route matchers ───────────────────────────────────────────────────────────\n\nfunction isGuestOnlyRoute(pathname: string, routes: string[]): boolean {\n return matchesAny(pathname, routes);\n}\n\n/**\n * Matches a pathname against a list of patterns.\n * Supports wildcards: \"/dashboard*\" matches \"/dashboard\", \"/dashboard/\", \"/dashboard/settings\"\n */\nfunction matchesAny(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => matchRoute(pathname, pattern));\n}\n\nfunction matchRoute(pathname: string, pattern: string): boolean {\n if (pattern.endsWith(\"*\")) {\n const base = pattern.slice(0, -1); // e.g. \"/dashboard\"\n // matches \"/dashboard\", \"/dashboard/\", \"/dashboard/anything\"\n return pathname === base || pathname.startsWith(base + \"/\") || pathname.startsWith(base);\n }\n return pathname === pattern;\n}\n","import type { AuthConfig, AuthTokens, LoginResponse } from \"../types\";\nimport { encrypt, decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n json(): Promise<unknown>;\n cookies: { get(name: string): { value: string } | undefined };\n};\n\n/**\n * Creates Next.js Route Handlers for login, logout, session, and refresh.\n * Mount these at `app/api/auth/[action]/route.ts`.\n *\n * All encryption happens server-side — the secret never leaves the server.\n *\n * @example\n * // app/api/auth/[action]/route.ts\n * import { createAuthHandlers } from \"next-token-auth/server\";\n * import { authConfig } from \"@/lib/auth\";\n *\n * export const { GET, POST } = createAuthHandlers(authConfig);\n */\nexport function createAuthHandlers<User = unknown>(config: AuthConfig<User>) {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n\n return {\n POST: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/login ─────────────────────────────────────────────────────\n if (action === \"login\") {\n const body = await req.json();\n const fetchFn = config.fetchFn ?? fetch;\n\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.login}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const text = await res.text();\n return NextResponse.json({ error: text }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const tokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(tokens), config.secret);\n const maxAge = tokens.refreshTokenExpiresAt\n ? Math.floor((tokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n // Fetch user from /me endpoint if not included in login response\n let user: User | null = data.user ?? null;\n if (!user && config.endpoints.me) {\n try {\n const meRes = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (meRes.ok) user = (await meRes.json()) as User;\n } catch {\n // User fetch failed — continue without user data\n }\n }\n\n return NextResponse.json(\n { ok: true, user },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n // ── /api/auth/logout ────────────────────────────────────────────────────\n if (action === \"logout\") {\n if (config.endpoints.logout) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n await fetchFn(`${config.baseUrl}${config.endpoints.logout}`, {\n method: \"POST\",\n });\n } catch {\n // Best-effort\n }\n }\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": `${cookieName}=; Max-Age=0; Path=/`,\n },\n }\n );\n }\n\n // ── /api/auth/refresh ───────────────────────────────────────────────────\n if (action === \"refresh\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ error: \"No session\" }, { status: 401 });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ error: \"Invalid session\" }, { status: 401 });\n }\n\n if (tokens.refreshTokenExpiresAt && Date.now() >= tokens.refreshTokenExpiresAt) {\n return NextResponse.json({ error: \"Refresh token expired\" }, { status: 401 });\n }\n\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.refresh}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) {\n return NextResponse.json({ error: \"Refresh failed\" }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const newTokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(newTokens), config.secret);\n const maxAge = newTokens.refreshTokenExpiresAt\n ? Math.floor((newTokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n\n GET: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/session ───────────────────────────────────────────────────\n if (action === \"session\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? Date.now() >= tokens.refreshTokenExpiresAt\n : false;\n\n if (refreshExpired) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n // Fetch user from backend\n let user: User | null = null;\n if (config.endpoints.me) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (res.ok) user = (await res.json()) as User;\n } catch {\n // User fetch failed — still return authenticated: true if tokens are valid\n }\n }\n\n return NextResponse.json({ user, isAuthenticated: true });\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction buildTokens<User>(\n data: LoginResponse<User>,\n config: AuthConfig<User>\n): AuthTokens {\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n const configAccess = config.expiry?.accessTokenExpiresIn;\n const configRefresh = config.expiry?.refreshTokenExpiresIn;\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(data, configAccess, strategy),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(data, configRefresh, strategy),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/crypto.ts","../../src/utils/expiry.ts","../../src/server/getServerSession.ts","../../src/server/getLayoutSession.ts","../../src/server/withAuth.ts","../../src/server/middleware.ts","../../src/server/handlers.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Lightweight symmetric encryption using AES-GCM via the Web Crypto API.\n * Works in both browser and Node.js (>=18) / Edge runtimes.\n */\n\nconst ALGO = \"AES-GCM\";\nconst IV_LENGTH = 12; // bytes\n\nfunction getTextEncoder() {\n return new TextEncoder();\n}\n\nfunction getTextDecoder() {\n return new TextDecoder();\n}\n\nasync function deriveKey(secret: string): Promise<CryptoKey> {\n if (!secret) {\n throw new Error(\n \"[next-token-auth] `secret` is undefined. \" +\n \"If using cookie storage, ensure AUTH_SECRET is set in your environment.\"\n );\n }\n const raw = getTextEncoder().encode(secret.padEnd(32, \"0\").slice(0, 32));\n return crypto.subtle.importKey(\"raw\", raw, { name: ALGO }, false, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\n/**\n * Encrypts a plaintext string using AES-GCM.\n * Returns a base64url-encoded string: `<iv>.<ciphertext>`\n */\nexport async function encrypt(data: string, secret: string): Promise<string> {\n const key = await deriveKey(secret);\n const ivArray = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n // Ensure we have a plain ArrayBuffer for SubtleCrypto\n const iv = ivArray.buffer.slice(0, IV_LENGTH) as ArrayBuffer;\n const encoded = getTextEncoder().encode(data);\n\n const cipherBuffer = await crypto.subtle.encrypt({ name: ALGO, iv }, key, encoded);\n\n const ivB64 = bufferToBase64(new Uint8Array(iv));\n const cipherB64 = bufferToBase64(new Uint8Array(cipherBuffer));\n return `${ivB64}.${cipherB64}`;\n}\n\n/**\n * Decrypts a string produced by `encrypt`.\n */\nexport async function decrypt(data: string, secret: string): Promise<string> {\n const [ivB64, cipherB64] = data.split(\".\");\n if (!ivB64 || !cipherB64) {\n throw new Error(\"decrypt: invalid ciphertext format\");\n }\n\n const key = await deriveKey(secret);\n const ivBytes = base64ToBuffer(ivB64);\n const iv = ivBytes.buffer.slice(\n ivBytes.byteOffset,\n ivBytes.byteOffset + ivBytes.byteLength\n ) as ArrayBuffer;\n\n const cipherBytes = base64ToBuffer(cipherB64);\n const cipherBuffer = cipherBytes.buffer.slice(\n cipherBytes.byteOffset,\n cipherBytes.byteOffset + cipherBytes.byteLength\n ) as ArrayBuffer;\n\n const plainBuffer = await crypto.subtle.decrypt({ name: ALGO, iv }, key, cipherBuffer);\n\n return getTextDecoder().decode(plainBuffer);\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction bufferToBase64(buffer: Uint8Array): string {\n return btoa(String.fromCharCode(...buffer))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nfunction base64ToBuffer(b64: string): Uint8Array {\n const padded = b64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded);\n return Uint8Array.from(binary, (c) => c.charCodeAt(0));\n}\n","import type { ExpiryInput, ExpiryStrategy, LoginResponse } from \"../types\";\n\nconst UNIT_MAP: Record<string, number> = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n w: 604800,\n};\n\n/**\n * Parses an expiry value into seconds.\n * Accepts:\n * - number → treated as seconds\n * - string → e.g. \"15m\", \"2h\", \"2d\", \"7d\", \"1w\"\n *\n * @throws if the format is unrecognised\n */\nexport function parseExpiry(input?: ExpiryInput): number {\n if (input === undefined || input === null) {\n throw new Error(\"parseExpiry: no expiry value provided\");\n }\n\n if (typeof input === \"number\") {\n if (input <= 0) throw new Error(\"parseExpiry: value must be positive\");\n return input;\n }\n\n const trimmed = input.trim();\n\n // Pure numeric string\n if (/^\\d+$/.test(trimmed)) {\n return parseInt(trimmed, 10);\n }\n\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*([smhdw])$/i);\n if (!match) {\n throw new Error(\n `parseExpiry: unrecognised format \"${input}\". ` +\n `Expected a number or a string like \"15m\", \"2h\", \"2d\", \"7d\", \"1w\".`\n );\n }\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n return Math.floor(value * UNIT_MAP[unit]);\n}\n\n/**\n * Safely parses an expiry value, returning a fallback on failure.\n */\nexport function safeParseExpiry(\n input?: ExpiryInput,\n fallbackSeconds = 900\n): number {\n try {\n return parseExpiry(input);\n } catch {\n return fallbackSeconds;\n }\n}\n\n/**\n * Resolves the access token expiry timestamp (ms) from a login response\n * using the configured strategy.\n */\nexport function resolveAccessTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number {\n const now = Date.now();\n\n const fromBackend =\n response.accessTokenExpiresIn ?? response.expiresIn ?? undefined;\n\n if (strategy === \"backend\") {\n if (fromBackend === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"backend\" but API returned no expiry'\n );\n }\n return now + parseExpiry(fromBackend) * 1000;\n }\n\n if (strategy === \"config\") {\n if (configExpiry === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"config\" but no expiry configured'\n );\n }\n return now + parseExpiry(configExpiry) * 1000;\n }\n\n // hybrid: backend first, fallback to config\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n // Last resort: 15 minutes\n return now + 900 * 1000;\n}\n\n/**\n * Resolves the refresh token expiry timestamp (ms).\n */\nexport function resolveRefreshTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number | undefined {\n const now = Date.now();\n const fromBackend = response.refreshTokenExpiresIn;\n\n if (strategy === \"backend\") {\n return fromBackend !== undefined\n ? now + parseExpiry(fromBackend) * 1000\n : undefined;\n }\n\n if (strategy === \"config\") {\n return configExpiry !== undefined\n ? now + parseExpiry(configExpiry) * 1000\n : undefined;\n }\n\n // hybrid\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n return undefined;\n}\n","import type { AuthConfig, AuthSession, AuthTokens, LoginResponse } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n cookies: {\n get(name: string): { value: string } | undefined;\n };\n};\n\n/**\n * Retrieves and validates the auth session on the server side.\n * Reads the encrypted session cookie, validates token expiry,\n * and refreshes if needed.\n *\n * Compatible with Next.js App Router (NextRequest) and Pages Router (IncomingMessage).\n *\n * @example\n * // app/dashboard/page.tsx\n * import { getServerSession } from \"next-token-auth/server\";\n *\n * export default async function Page({ request }) {\n * const session = await getServerSession(request, config);\n * if (!session.isAuthenticated) redirect(\"/login\");\n * }\n */\nexport async function getServerSession<User = unknown>(\n req: NextRequest,\n config: AuthConfig<User>\n): Promise<AuthSession<User>> {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = req.cookies.get(cookieName)?.value;\n\n if (!cookieValue) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n let tokens: AuthTokens | null = null;\n\n try {\n const json = await decrypt(cookieValue, config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n const now = Date.now();\n const threshold = (config.refreshThreshold ?? 60) * 1000;\n const accessExpired = now >= tokens.accessTokenExpiresAt - threshold;\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n\n // Both expired → clear session\n if (accessExpired && refreshExpired) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n // Access expired but refresh valid → attempt server-side refresh\n if (accessExpired && !refreshExpired) {\n const refreshed = await serverRefresh<User>(tokens, config);\n if (!refreshed) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n tokens = refreshed;\n }\n\n const user = await fetchUser<User>(tokens.accessToken, config);\n\n return {\n user,\n tokens,\n isAuthenticated: true,\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nasync function serverRefresh<User>(\n tokens: AuthTokens,\n config: AuthConfig<User>\n): Promise<AuthTokens | null> {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const refreshPath = config.endpoints.refresh.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${refreshPath}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as LoginResponse<User>;\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(\n data,\n config.expiry?.accessTokenExpiresIn,\n strategy\n ),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(\n data,\n config.expiry?.refreshTokenExpiresIn,\n strategy\n ),\n };\n } catch {\n return null;\n }\n}\n\nasync function fetchUser<User>(\n accessToken: string,\n config: AuthConfig<User>\n): Promise<User | null> {\n if (!config.endpoints.me) return null;\n\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const mePath = config.endpoints.me.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${mePath}`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!res.ok) return null;\n return (await res.json()) as User;\n } catch {\n return null;\n }\n}\n","import type { AuthConfig, AuthSession, AuthTokens } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\n\n/**\n * Reads the session from the cookie store inside a Server Component or layout.\n * Use this in app/layout.tsx to pre-seed AuthProvider and avoid the auth flash.\n *\n * @example\n * // app/layout.tsx\n * import { getLayoutSession } from \"next-token-auth/server\";\n * import { authConfig } from \"@/lib/auth\";\n *\n * export default async function RootLayout({ children }) {\n * const session = await getLayoutSession(authConfig);\n * return (\n * <AuthProvider config={clientConfig} initialSession={session}>\n * {children}\n * </AuthProvider>\n * );\n * }\n */\nexport async function getLayoutSession<User = unknown>(\n config: AuthConfig<User>\n): Promise<AuthSession<User>> {\n const empty: AuthSession<User> = {\n user: null,\n tokens: null,\n isAuthenticated: false,\n };\n\n try {\n const { cookies } = await import(\"next/headers\");\n const cookieStore = await cookies();\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n const raw = cookieStore.get(cookieName)?.value;\n\n if (!raw) return empty;\n\n // Decrypt the cookie using the server-side secret\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return empty;\n }\n\n // Reject if refresh token has expired\n if (tokens.refreshTokenExpiresAt && Date.now() >= tokens.refreshTokenExpiresAt) {\n return empty;\n }\n\n // Fetch user info using the access token\n let user: User | null = null;\n if (config.endpoints.me) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (res.ok) user = (await res.json()) as User;\n } catch {\n // User fetch failed, but token exists — still authenticated\n }\n }\n\n // Return session without exposing raw tokens to the client\n return { user, tokens: null, isAuthenticated: true };\n } catch {\n return empty;\n }\n}\n","import type { AuthConfig, AuthSession } from \"../types\";\nimport { getServerSession } from \"./getServerSession\";\n\ntype NextRequest = {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string };\n};\n\ntype NextResponse = {\n redirect(url: URL): NextResponse;\n next(): NextResponse;\n};\n\ntype RouteHandler<User = unknown> = (\n req: NextRequest,\n session: AuthSession<User>\n) => Promise<Response> | Response;\n\n/**\n * Higher-order function that wraps a Next.js route handler with auth protection.\n * Redirects unauthenticated requests to the login page.\n *\n * @example\n * // app/api/protected/route.ts\n * export const GET = withAuth(config, async (req, session) => {\n * return Response.json({ user: session.user });\n * });\n */\nexport function withAuth<User = unknown>(\n config: AuthConfig<User>,\n handler: RouteHandler<User>,\n options: { redirectTo?: string } = {}\n) {\n return async (req: NextRequest): Promise<Response> => {\n const session = await getServerSession<User>(req, config);\n\n if (!session.isAuthenticated) {\n const redirectTo = options.redirectTo ?? \"/login\";\n const loginUrl = new URL(redirectTo, `https://${req.nextUrl.pathname}`);\n return Response.redirect(loginUrl);\n }\n\n return handler(req, session);\n };\n}\n","import type { AuthConfig } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport type { AuthTokens } from \"../types\";\n\n/**\n * Next.js middleware factory for route protection.\n *\n * @example\n * // middleware.ts (project root)\n * import { authMiddleware } from \"next-token-auth/server\";\n * import { authConfig } from \"./lib/auth\";\n *\n * export const middleware = authMiddleware(authConfig);\n *\n * export const config = {\n * matcher: [\"/auth/login\", \"/auth/register\", \"/dashboard*\", \"/profile*\"],\n * };\n */\nexport function authMiddleware<User = unknown>(authConfig: AuthConfig<User>) {\n return async function middleware(request: {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string; origin: string };\n url: string;\n }): Promise<Response> {\n const { NextResponse } = await import(\"next/server\");\n\n const pathname = request.nextUrl.pathname;\n const cookieName = authConfig.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = request.cookies.get(cookieName)?.value;\n\n const isAuthenticated = await checkSession(cookieValue, authConfig.secret);\n\n // ── Guest-only routes ────────────────────────────────────────────────────\n // Accessible only when NOT authenticated.\n // Authenticated users are redirected to redirectAuthenticatedTo.\n const guestOnlyRoutes = authConfig.routes?.guestOnly ?? [];\n if (isGuestOnlyRoute(pathname, guestOnlyRoutes)) {\n if (isAuthenticated) {\n const redirectTo = authConfig.routes?.redirectAuthenticatedTo ?? \"/dashboard\";\n return NextResponse.redirect(new URL(redirectTo, request.nextUrl.origin));\n }\n return NextResponse.next();\n }\n\n // ── Public routes ────────────────────────────────────────────────────────\n const publicRoutes = authConfig.routes?.public ?? [];\n if (matchesAny(pathname, publicRoutes)) {\n return NextResponse.next();\n }\n\n // ── Protected routes ─────────────────────────────────────────────────────\n const protectedRoutes = authConfig.routes?.protected ?? [];\n const requiresAuth =\n protectedRoutes.length === 0 || matchesAny(pathname, protectedRoutes);\n\n if (!requiresAuth) {\n return NextResponse.next();\n }\n\n if (!isAuthenticated) {\n // Use the configured login endpoint path, falling back to \"/login\"\n const loginPath = authConfig.routes?.loginPath ?? \"/login\";\n return NextResponse.redirect(new URL(loginPath, request.nextUrl.origin));\n }\n\n return NextResponse.next();\n };\n}\n\n// ─── Session check ────────────────────────────────────────────────────────────\n\nasync function checkSession(\n cookieValue: string | undefined,\n secret: string\n): Promise<boolean> {\n if (!cookieValue) return false;\n\n try {\n const json = await decrypt(cookieValue, secret);\n const tokens = JSON.parse(json) as AuthTokens;\n const now = Date.now();\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n return !refreshExpired;\n } catch {\n return false;\n }\n}\n\n// ─── Route matchers ───────────────────────────────────────────────────────────\n\nfunction isGuestOnlyRoute(pathname: string, routes: string[]): boolean {\n return matchesAny(pathname, routes);\n}\n\n/**\n * Matches a pathname against a list of patterns.\n * Supports wildcards: \"/dashboard*\" matches \"/dashboard\", \"/dashboard/\", \"/dashboard/settings\"\n */\nfunction matchesAny(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => matchRoute(pathname, pattern));\n}\n\nfunction matchRoute(pathname: string, pattern: string): boolean {\n if (pattern.endsWith(\"*\")) {\n const base = pattern.slice(0, -1); // e.g. \"/dashboard\"\n // matches \"/dashboard\", \"/dashboard/\", \"/dashboard/anything\"\n return pathname === base || pathname.startsWith(base + \"/\") || pathname.startsWith(base);\n }\n return pathname === pattern;\n}\n","import type { AuthConfig, AuthTokens, LoginResponse } from \"../types\";\nimport { encrypt, decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n json(): Promise<unknown>;\n cookies: { get(name: string): { value: string } | undefined };\n};\n\n/**\n * Creates Next.js Route Handlers for login, logout, session, and refresh.\n * Mount these at `app/api/auth/[action]/route.ts`.\n *\n * All encryption happens server-side — the secret never leaves the server.\n *\n * @example\n * // app/api/auth/[action]/route.ts\n * import { createAuthHandlers } from \"next-token-auth/server\";\n * import { authConfig } from \"@/lib/auth\";\n *\n * export const { GET, POST } = createAuthHandlers(authConfig);\n */\nexport function createAuthHandlers<User = unknown>(config: AuthConfig<User>) {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n\n return {\n POST: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/login ─────────────────────────────────────────────────────\n if (action === \"login\") {\n const body = await req.json();\n const fetchFn = config.fetchFn ?? fetch;\n\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.login}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const text = await res.text();\n return NextResponse.json({ error: text }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const tokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(tokens), config.secret);\n const maxAge = tokens.refreshTokenExpiresAt\n ? Math.floor((tokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n // Fetch user from /me endpoint if not included in login response\n let user: User | null = data.user ?? null;\n if (!user && config.endpoints.me) {\n try {\n const meRes = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (meRes.ok) user = (await meRes.json()) as User;\n } catch {\n // User fetch failed — continue without user data\n }\n }\n\n return NextResponse.json(\n { ok: true, user },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n // ── /api/auth/logout ────────────────────────────────────────────────────\n if (action === \"logout\") {\n if (config.endpoints.logout) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n await fetchFn(`${config.baseUrl}${config.endpoints.logout}`, {\n method: \"POST\",\n });\n } catch {\n // Best-effort\n }\n }\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": `${cookieName}=; Max-Age=0; Path=/`,\n },\n }\n );\n }\n\n // ── /api/auth/refresh ───────────────────────────────────────────────────\n if (action === \"refresh\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ error: \"No session\" }, { status: 401 });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ error: \"Invalid session\" }, { status: 401 });\n }\n\n if (tokens.refreshTokenExpiresAt && Date.now() >= tokens.refreshTokenExpiresAt) {\n return NextResponse.json({ error: \"Refresh token expired\" }, { status: 401 });\n }\n\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.refresh}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) {\n return NextResponse.json({ error: \"Refresh failed\" }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const newTokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(newTokens), config.secret);\n const maxAge = newTokens.refreshTokenExpiresAt\n ? Math.floor((newTokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n\n GET: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/session ───────────────────────────────────────────────────\n if (action === \"session\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? Date.now() >= tokens.refreshTokenExpiresAt\n : false;\n\n if (refreshExpired) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n // Fetch user from backend\n let user: User | null = null;\n if (config.endpoints.me) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (res.ok) user = (await res.json()) as User;\n } catch {\n // User fetch failed — still return authenticated: true if tokens are valid\n }\n }\n\n return NextResponse.json({ user, isAuthenticated: true });\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction buildTokens<User>(\n data: LoginResponse<User>,\n config: AuthConfig<User>\n): AuthTokens {\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n const configAccess = config.expiry?.accessTokenExpiresIn;\n const configRefresh = config.expiry?.refreshTokenExpiresIn;\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(data, configAccess, strategy),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(data, configRefresh, strategy),\n };\n}\n"]}
|
package/dist/server/index.mjs
CHANGED
|
@@ -221,6 +221,46 @@ async function fetchUser(accessToken, config) {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
// src/server/getLayoutSession.ts
|
|
225
|
+
async function getLayoutSession(config) {
|
|
226
|
+
const empty = {
|
|
227
|
+
user: null,
|
|
228
|
+
tokens: null,
|
|
229
|
+
isAuthenticated: false
|
|
230
|
+
};
|
|
231
|
+
try {
|
|
232
|
+
const { cookies } = await import('next/headers');
|
|
233
|
+
const cookieStore = await cookies();
|
|
234
|
+
const cookieName = config.token.cookieName ?? "next-token-auth.session";
|
|
235
|
+
const raw = cookieStore.get(cookieName)?.value;
|
|
236
|
+
if (!raw) return empty;
|
|
237
|
+
let tokens;
|
|
238
|
+
try {
|
|
239
|
+
const json = await decrypt(decodeURIComponent(raw), config.secret);
|
|
240
|
+
tokens = JSON.parse(json);
|
|
241
|
+
} catch {
|
|
242
|
+
return empty;
|
|
243
|
+
}
|
|
244
|
+
if (tokens.refreshTokenExpiresAt && Date.now() >= tokens.refreshTokenExpiresAt) {
|
|
245
|
+
return empty;
|
|
246
|
+
}
|
|
247
|
+
let user = null;
|
|
248
|
+
if (config.endpoints.me) {
|
|
249
|
+
try {
|
|
250
|
+
const fetchFn = config.fetchFn ?? fetch;
|
|
251
|
+
const res = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {
|
|
252
|
+
headers: { Authorization: `Bearer ${tokens.accessToken}` }
|
|
253
|
+
});
|
|
254
|
+
if (res.ok) user = await res.json();
|
|
255
|
+
} catch {
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return { user, tokens: null, isAuthenticated: true };
|
|
259
|
+
} catch {
|
|
260
|
+
return empty;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
224
264
|
// src/server/withAuth.ts
|
|
225
265
|
function withAuth(config, handler, options = {}) {
|
|
226
266
|
return async (req) => {
|
|
@@ -460,6 +500,6 @@ function buildTokens(data, config) {
|
|
|
460
500
|
};
|
|
461
501
|
}
|
|
462
502
|
|
|
463
|
-
export { authMiddleware, createAuthHandlers, getServerSession, withAuth };
|
|
503
|
+
export { authMiddleware, createAuthHandlers, getLayoutSession, getServerSession, withAuth };
|
|
464
504
|
//# sourceMappingURL=index.mjs.map
|
|
465
505
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/crypto.ts","../../src/utils/expiry.ts","../../src/server/getServerSession.ts","../../src/server/withAuth.ts","../../src/server/middleware.ts","../../src/server/handlers.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Lightweight symmetric encryption using AES-GCM via the Web Crypto API.\n * Works in both browser and Node.js (>=18) / Edge runtimes.\n */\n\nconst ALGO = \"AES-GCM\";\nconst IV_LENGTH = 12; // bytes\n\nfunction getTextEncoder() {\n return new TextEncoder();\n}\n\nfunction getTextDecoder() {\n return new TextDecoder();\n}\n\nasync function deriveKey(secret: string): Promise<CryptoKey> {\n if (!secret) {\n throw new Error(\n \"[next-token-auth] `secret` is undefined. \" +\n \"If using cookie storage, ensure AUTH_SECRET is set in your environment.\"\n );\n }\n const raw = getTextEncoder().encode(secret.padEnd(32, \"0\").slice(0, 32));\n return crypto.subtle.importKey(\"raw\", raw, { name: ALGO }, false, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\n/**\n * Encrypts a plaintext string using AES-GCM.\n * Returns a base64url-encoded string: `<iv>.<ciphertext>`\n */\nexport async function encrypt(data: string, secret: string): Promise<string> {\n const key = await deriveKey(secret);\n const ivArray = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n // Ensure we have a plain ArrayBuffer for SubtleCrypto\n const iv = ivArray.buffer.slice(0, IV_LENGTH) as ArrayBuffer;\n const encoded = getTextEncoder().encode(data);\n\n const cipherBuffer = await crypto.subtle.encrypt({ name: ALGO, iv }, key, encoded);\n\n const ivB64 = bufferToBase64(new Uint8Array(iv));\n const cipherB64 = bufferToBase64(new Uint8Array(cipherBuffer));\n return `${ivB64}.${cipherB64}`;\n}\n\n/**\n * Decrypts a string produced by `encrypt`.\n */\nexport async function decrypt(data: string, secret: string): Promise<string> {\n const [ivB64, cipherB64] = data.split(\".\");\n if (!ivB64 || !cipherB64) {\n throw new Error(\"decrypt: invalid ciphertext format\");\n }\n\n const key = await deriveKey(secret);\n const ivBytes = base64ToBuffer(ivB64);\n const iv = ivBytes.buffer.slice(\n ivBytes.byteOffset,\n ivBytes.byteOffset + ivBytes.byteLength\n ) as ArrayBuffer;\n\n const cipherBytes = base64ToBuffer(cipherB64);\n const cipherBuffer = cipherBytes.buffer.slice(\n cipherBytes.byteOffset,\n cipherBytes.byteOffset + cipherBytes.byteLength\n ) as ArrayBuffer;\n\n const plainBuffer = await crypto.subtle.decrypt({ name: ALGO, iv }, key, cipherBuffer);\n\n return getTextDecoder().decode(plainBuffer);\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction bufferToBase64(buffer: Uint8Array): string {\n return btoa(String.fromCharCode(...buffer))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nfunction base64ToBuffer(b64: string): Uint8Array {\n const padded = b64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded);\n return Uint8Array.from(binary, (c) => c.charCodeAt(0));\n}\n","import type { ExpiryInput, ExpiryStrategy, LoginResponse } from \"../types\";\n\nconst UNIT_MAP: Record<string, number> = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n w: 604800,\n};\n\n/**\n * Parses an expiry value into seconds.\n * Accepts:\n * - number → treated as seconds\n * - string → e.g. \"15m\", \"2h\", \"2d\", \"7d\", \"1w\"\n *\n * @throws if the format is unrecognised\n */\nexport function parseExpiry(input?: ExpiryInput): number {\n if (input === undefined || input === null) {\n throw new Error(\"parseExpiry: no expiry value provided\");\n }\n\n if (typeof input === \"number\") {\n if (input <= 0) throw new Error(\"parseExpiry: value must be positive\");\n return input;\n }\n\n const trimmed = input.trim();\n\n // Pure numeric string\n if (/^\\d+$/.test(trimmed)) {\n return parseInt(trimmed, 10);\n }\n\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*([smhdw])$/i);\n if (!match) {\n throw new Error(\n `parseExpiry: unrecognised format \"${input}\". ` +\n `Expected a number or a string like \"15m\", \"2h\", \"2d\", \"7d\", \"1w\".`\n );\n }\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n return Math.floor(value * UNIT_MAP[unit]);\n}\n\n/**\n * Safely parses an expiry value, returning a fallback on failure.\n */\nexport function safeParseExpiry(\n input?: ExpiryInput,\n fallbackSeconds = 900\n): number {\n try {\n return parseExpiry(input);\n } catch {\n return fallbackSeconds;\n }\n}\n\n/**\n * Resolves the access token expiry timestamp (ms) from a login response\n * using the configured strategy.\n */\nexport function resolveAccessTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number {\n const now = Date.now();\n\n const fromBackend =\n response.accessTokenExpiresIn ?? response.expiresIn ?? undefined;\n\n if (strategy === \"backend\") {\n if (fromBackend === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"backend\" but API returned no expiry'\n );\n }\n return now + parseExpiry(fromBackend) * 1000;\n }\n\n if (strategy === \"config\") {\n if (configExpiry === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"config\" but no expiry configured'\n );\n }\n return now + parseExpiry(configExpiry) * 1000;\n }\n\n // hybrid: backend first, fallback to config\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n // Last resort: 15 minutes\n return now + 900 * 1000;\n}\n\n/**\n * Resolves the refresh token expiry timestamp (ms).\n */\nexport function resolveRefreshTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number | undefined {\n const now = Date.now();\n const fromBackend = response.refreshTokenExpiresIn;\n\n if (strategy === \"backend\") {\n return fromBackend !== undefined\n ? now + parseExpiry(fromBackend) * 1000\n : undefined;\n }\n\n if (strategy === \"config\") {\n return configExpiry !== undefined\n ? now + parseExpiry(configExpiry) * 1000\n : undefined;\n }\n\n // hybrid\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n return undefined;\n}\n","import type { AuthConfig, AuthSession, AuthTokens, LoginResponse } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n cookies: {\n get(name: string): { value: string } | undefined;\n };\n};\n\n/**\n * Retrieves and validates the auth session on the server side.\n * Reads the encrypted session cookie, validates token expiry,\n * and refreshes if needed.\n *\n * Compatible with Next.js App Router (NextRequest) and Pages Router (IncomingMessage).\n *\n * @example\n * // app/dashboard/page.tsx\n * import { getServerSession } from \"next-token-auth/server\";\n *\n * export default async function Page({ request }) {\n * const session = await getServerSession(request, config);\n * if (!session.isAuthenticated) redirect(\"/login\");\n * }\n */\nexport async function getServerSession<User = unknown>(\n req: NextRequest,\n config: AuthConfig<User>\n): Promise<AuthSession<User>> {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = req.cookies.get(cookieName)?.value;\n\n if (!cookieValue) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n let tokens: AuthTokens | null = null;\n\n try {\n const json = await decrypt(cookieValue, config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n const now = Date.now();\n const threshold = (config.refreshThreshold ?? 60) * 1000;\n const accessExpired = now >= tokens.accessTokenExpiresAt - threshold;\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n\n // Both expired → clear session\n if (accessExpired && refreshExpired) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n // Access expired but refresh valid → attempt server-side refresh\n if (accessExpired && !refreshExpired) {\n const refreshed = await serverRefresh<User>(tokens, config);\n if (!refreshed) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n tokens = refreshed;\n }\n\n const user = await fetchUser<User>(tokens.accessToken, config);\n\n return {\n user,\n tokens,\n isAuthenticated: true,\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nasync function serverRefresh<User>(\n tokens: AuthTokens,\n config: AuthConfig<User>\n): Promise<AuthTokens | null> {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const refreshPath = config.endpoints.refresh.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${refreshPath}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as LoginResponse<User>;\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(\n data,\n config.expiry?.accessTokenExpiresIn,\n strategy\n ),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(\n data,\n config.expiry?.refreshTokenExpiresIn,\n strategy\n ),\n };\n } catch {\n return null;\n }\n}\n\nasync function fetchUser<User>(\n accessToken: string,\n config: AuthConfig<User>\n): Promise<User | null> {\n if (!config.endpoints.me) return null;\n\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const mePath = config.endpoints.me.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${mePath}`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!res.ok) return null;\n return (await res.json()) as User;\n } catch {\n return null;\n }\n}\n","import type { AuthConfig, AuthSession } from \"../types\";\nimport { getServerSession } from \"./getServerSession\";\n\ntype NextRequest = {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string };\n};\n\ntype NextResponse = {\n redirect(url: URL): NextResponse;\n next(): NextResponse;\n};\n\ntype RouteHandler<User = unknown> = (\n req: NextRequest,\n session: AuthSession<User>\n) => Promise<Response> | Response;\n\n/**\n * Higher-order function that wraps a Next.js route handler with auth protection.\n * Redirects unauthenticated requests to the login page.\n *\n * @example\n * // app/api/protected/route.ts\n * export const GET = withAuth(config, async (req, session) => {\n * return Response.json({ user: session.user });\n * });\n */\nexport function withAuth<User = unknown>(\n config: AuthConfig<User>,\n handler: RouteHandler<User>,\n options: { redirectTo?: string } = {}\n) {\n return async (req: NextRequest): Promise<Response> => {\n const session = await getServerSession<User>(req, config);\n\n if (!session.isAuthenticated) {\n const redirectTo = options.redirectTo ?? \"/login\";\n const loginUrl = new URL(redirectTo, `https://${req.nextUrl.pathname}`);\n return Response.redirect(loginUrl);\n }\n\n return handler(req, session);\n };\n}\n","import type { AuthConfig } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport type { AuthTokens } from \"../types\";\n\n/**\n * Next.js middleware factory for route protection.\n *\n * @example\n * // middleware.ts (project root)\n * import { authMiddleware } from \"next-token-auth/server\";\n * import { authConfig } from \"./lib/auth\";\n *\n * export const middleware = authMiddleware(authConfig);\n *\n * export const config = {\n * matcher: [\"/auth/login\", \"/auth/register\", \"/dashboard*\", \"/profile*\"],\n * };\n */\nexport function authMiddleware<User = unknown>(authConfig: AuthConfig<User>) {\n return async function middleware(request: {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string; origin: string };\n url: string;\n }): Promise<Response> {\n const { NextResponse } = await import(\"next/server\");\n\n const pathname = request.nextUrl.pathname;\n const cookieName = authConfig.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = request.cookies.get(cookieName)?.value;\n\n const isAuthenticated = await checkSession(cookieValue, authConfig.secret);\n\n // ── Guest-only routes ────────────────────────────────────────────────────\n // Accessible only when NOT authenticated.\n // Authenticated users are redirected to redirectAuthenticatedTo.\n const guestOnlyRoutes = authConfig.routes?.guestOnly ?? [];\n if (isGuestOnlyRoute(pathname, guestOnlyRoutes)) {\n if (isAuthenticated) {\n const redirectTo = authConfig.routes?.redirectAuthenticatedTo ?? \"/dashboard\";\n return NextResponse.redirect(new URL(redirectTo, request.nextUrl.origin));\n }\n return NextResponse.next();\n }\n\n // ── Public routes ────────────────────────────────────────────────────────\n const publicRoutes = authConfig.routes?.public ?? [];\n if (matchesAny(pathname, publicRoutes)) {\n return NextResponse.next();\n }\n\n // ── Protected routes ─────────────────────────────────────────────────────\n const protectedRoutes = authConfig.routes?.protected ?? [];\n const requiresAuth =\n protectedRoutes.length === 0 || matchesAny(pathname, protectedRoutes);\n\n if (!requiresAuth) {\n return NextResponse.next();\n }\n\n if (!isAuthenticated) {\n // Use the configured login endpoint path, falling back to \"/login\"\n const loginPath = authConfig.routes?.loginPath ?? \"/login\";\n return NextResponse.redirect(new URL(loginPath, request.nextUrl.origin));\n }\n\n return NextResponse.next();\n };\n}\n\n// ─── Session check ────────────────────────────────────────────────────────────\n\nasync function checkSession(\n cookieValue: string | undefined,\n secret: string\n): Promise<boolean> {\n if (!cookieValue) return false;\n\n try {\n const json = await decrypt(cookieValue, secret);\n const tokens = JSON.parse(json) as AuthTokens;\n const now = Date.now();\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n return !refreshExpired;\n } catch {\n return false;\n }\n}\n\n// ─── Route matchers ───────────────────────────────────────────────────────────\n\nfunction isGuestOnlyRoute(pathname: string, routes: string[]): boolean {\n return matchesAny(pathname, routes);\n}\n\n/**\n * Matches a pathname against a list of patterns.\n * Supports wildcards: \"/dashboard*\" matches \"/dashboard\", \"/dashboard/\", \"/dashboard/settings\"\n */\nfunction matchesAny(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => matchRoute(pathname, pattern));\n}\n\nfunction matchRoute(pathname: string, pattern: string): boolean {\n if (pattern.endsWith(\"*\")) {\n const base = pattern.slice(0, -1); // e.g. \"/dashboard\"\n // matches \"/dashboard\", \"/dashboard/\", \"/dashboard/anything\"\n return pathname === base || pathname.startsWith(base + \"/\") || pathname.startsWith(base);\n }\n return pathname === pattern;\n}\n","import type { AuthConfig, AuthTokens, LoginResponse } from \"../types\";\nimport { encrypt, decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n json(): Promise<unknown>;\n cookies: { get(name: string): { value: string } | undefined };\n};\n\n/**\n * Creates Next.js Route Handlers for login, logout, session, and refresh.\n * Mount these at `app/api/auth/[action]/route.ts`.\n *\n * All encryption happens server-side — the secret never leaves the server.\n *\n * @example\n * // app/api/auth/[action]/route.ts\n * import { createAuthHandlers } from \"next-token-auth/server\";\n * import { authConfig } from \"@/lib/auth\";\n *\n * export const { GET, POST } = createAuthHandlers(authConfig);\n */\nexport function createAuthHandlers<User = unknown>(config: AuthConfig<User>) {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n\n return {\n POST: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/login ─────────────────────────────────────────────────────\n if (action === \"login\") {\n const body = await req.json();\n const fetchFn = config.fetchFn ?? fetch;\n\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.login}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const text = await res.text();\n return NextResponse.json({ error: text }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const tokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(tokens), config.secret);\n const maxAge = tokens.refreshTokenExpiresAt\n ? Math.floor((tokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n // Fetch user from /me endpoint if not included in login response\n let user: User | null = data.user ?? null;\n if (!user && config.endpoints.me) {\n try {\n const meRes = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (meRes.ok) user = (await meRes.json()) as User;\n } catch {\n // User fetch failed — continue without user data\n }\n }\n\n return NextResponse.json(\n { ok: true, user },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n // ── /api/auth/logout ────────────────────────────────────────────────────\n if (action === \"logout\") {\n if (config.endpoints.logout) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n await fetchFn(`${config.baseUrl}${config.endpoints.logout}`, {\n method: \"POST\",\n });\n } catch {\n // Best-effort\n }\n }\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": `${cookieName}=; Max-Age=0; Path=/`,\n },\n }\n );\n }\n\n // ── /api/auth/refresh ───────────────────────────────────────────────────\n if (action === \"refresh\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ error: \"No session\" }, { status: 401 });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ error: \"Invalid session\" }, { status: 401 });\n }\n\n if (tokens.refreshTokenExpiresAt && Date.now() >= tokens.refreshTokenExpiresAt) {\n return NextResponse.json({ error: \"Refresh token expired\" }, { status: 401 });\n }\n\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.refresh}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) {\n return NextResponse.json({ error: \"Refresh failed\" }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const newTokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(newTokens), config.secret);\n const maxAge = newTokens.refreshTokenExpiresAt\n ? Math.floor((newTokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n\n GET: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/session ───────────────────────────────────────────────────\n if (action === \"session\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? Date.now() >= tokens.refreshTokenExpiresAt\n : false;\n\n if (refreshExpired) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n // Fetch user from backend\n let user: User | null = null;\n if (config.endpoints.me) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (res.ok) user = (await res.json()) as User;\n } catch {\n // User fetch failed — still return authenticated: true if tokens are valid\n }\n }\n\n return NextResponse.json({ user, isAuthenticated: true });\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction buildTokens<User>(\n data: LoginResponse<User>,\n config: AuthConfig<User>\n): AuthTokens {\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n const configAccess = config.expiry?.accessTokenExpiresIn;\n const configRefresh = config.expiry?.refreshTokenExpiresIn;\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(data, configAccess, strategy),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(data, configRefresh, strategy),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/crypto.ts","../../src/utils/expiry.ts","../../src/server/getServerSession.ts","../../src/server/getLayoutSession.ts","../../src/server/withAuth.ts","../../src/server/middleware.ts","../../src/server/handlers.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Lightweight symmetric encryption using AES-GCM via the Web Crypto API.\n * Works in both browser and Node.js (>=18) / Edge runtimes.\n */\n\nconst ALGO = \"AES-GCM\";\nconst IV_LENGTH = 12; // bytes\n\nfunction getTextEncoder() {\n return new TextEncoder();\n}\n\nfunction getTextDecoder() {\n return new TextDecoder();\n}\n\nasync function deriveKey(secret: string): Promise<CryptoKey> {\n if (!secret) {\n throw new Error(\n \"[next-token-auth] `secret` is undefined. \" +\n \"If using cookie storage, ensure AUTH_SECRET is set in your environment.\"\n );\n }\n const raw = getTextEncoder().encode(secret.padEnd(32, \"0\").slice(0, 32));\n return crypto.subtle.importKey(\"raw\", raw, { name: ALGO }, false, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\n/**\n * Encrypts a plaintext string using AES-GCM.\n * Returns a base64url-encoded string: `<iv>.<ciphertext>`\n */\nexport async function encrypt(data: string, secret: string): Promise<string> {\n const key = await deriveKey(secret);\n const ivArray = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n // Ensure we have a plain ArrayBuffer for SubtleCrypto\n const iv = ivArray.buffer.slice(0, IV_LENGTH) as ArrayBuffer;\n const encoded = getTextEncoder().encode(data);\n\n const cipherBuffer = await crypto.subtle.encrypt({ name: ALGO, iv }, key, encoded);\n\n const ivB64 = bufferToBase64(new Uint8Array(iv));\n const cipherB64 = bufferToBase64(new Uint8Array(cipherBuffer));\n return `${ivB64}.${cipherB64}`;\n}\n\n/**\n * Decrypts a string produced by `encrypt`.\n */\nexport async function decrypt(data: string, secret: string): Promise<string> {\n const [ivB64, cipherB64] = data.split(\".\");\n if (!ivB64 || !cipherB64) {\n throw new Error(\"decrypt: invalid ciphertext format\");\n }\n\n const key = await deriveKey(secret);\n const ivBytes = base64ToBuffer(ivB64);\n const iv = ivBytes.buffer.slice(\n ivBytes.byteOffset,\n ivBytes.byteOffset + ivBytes.byteLength\n ) as ArrayBuffer;\n\n const cipherBytes = base64ToBuffer(cipherB64);\n const cipherBuffer = cipherBytes.buffer.slice(\n cipherBytes.byteOffset,\n cipherBytes.byteOffset + cipherBytes.byteLength\n ) as ArrayBuffer;\n\n const plainBuffer = await crypto.subtle.decrypt({ name: ALGO, iv }, key, cipherBuffer);\n\n return getTextDecoder().decode(plainBuffer);\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction bufferToBase64(buffer: Uint8Array): string {\n return btoa(String.fromCharCode(...buffer))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nfunction base64ToBuffer(b64: string): Uint8Array {\n const padded = b64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded);\n return Uint8Array.from(binary, (c) => c.charCodeAt(0));\n}\n","import type { ExpiryInput, ExpiryStrategy, LoginResponse } from \"../types\";\n\nconst UNIT_MAP: Record<string, number> = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n w: 604800,\n};\n\n/**\n * Parses an expiry value into seconds.\n * Accepts:\n * - number → treated as seconds\n * - string → e.g. \"15m\", \"2h\", \"2d\", \"7d\", \"1w\"\n *\n * @throws if the format is unrecognised\n */\nexport function parseExpiry(input?: ExpiryInput): number {\n if (input === undefined || input === null) {\n throw new Error(\"parseExpiry: no expiry value provided\");\n }\n\n if (typeof input === \"number\") {\n if (input <= 0) throw new Error(\"parseExpiry: value must be positive\");\n return input;\n }\n\n const trimmed = input.trim();\n\n // Pure numeric string\n if (/^\\d+$/.test(trimmed)) {\n return parseInt(trimmed, 10);\n }\n\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*([smhdw])$/i);\n if (!match) {\n throw new Error(\n `parseExpiry: unrecognised format \"${input}\". ` +\n `Expected a number or a string like \"15m\", \"2h\", \"2d\", \"7d\", \"1w\".`\n );\n }\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n return Math.floor(value * UNIT_MAP[unit]);\n}\n\n/**\n * Safely parses an expiry value, returning a fallback on failure.\n */\nexport function safeParseExpiry(\n input?: ExpiryInput,\n fallbackSeconds = 900\n): number {\n try {\n return parseExpiry(input);\n } catch {\n return fallbackSeconds;\n }\n}\n\n/**\n * Resolves the access token expiry timestamp (ms) from a login response\n * using the configured strategy.\n */\nexport function resolveAccessTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number {\n const now = Date.now();\n\n const fromBackend =\n response.accessTokenExpiresIn ?? response.expiresIn ?? undefined;\n\n if (strategy === \"backend\") {\n if (fromBackend === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"backend\" but API returned no expiry'\n );\n }\n return now + parseExpiry(fromBackend) * 1000;\n }\n\n if (strategy === \"config\") {\n if (configExpiry === undefined) {\n throw new Error(\n 'resolveAccessTokenExpiry: strategy is \"config\" but no expiry configured'\n );\n }\n return now + parseExpiry(configExpiry) * 1000;\n }\n\n // hybrid: backend first, fallback to config\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n // Last resort: 15 minutes\n return now + 900 * 1000;\n}\n\n/**\n * Resolves the refresh token expiry timestamp (ms).\n */\nexport function resolveRefreshTokenExpiry(\n response: LoginResponse,\n configExpiry?: ExpiryInput,\n strategy: ExpiryStrategy = \"hybrid\"\n): number | undefined {\n const now = Date.now();\n const fromBackend = response.refreshTokenExpiresIn;\n\n if (strategy === \"backend\") {\n return fromBackend !== undefined\n ? now + parseExpiry(fromBackend) * 1000\n : undefined;\n }\n\n if (strategy === \"config\") {\n return configExpiry !== undefined\n ? now + parseExpiry(configExpiry) * 1000\n : undefined;\n }\n\n // hybrid\n if (fromBackend !== undefined) {\n return now + safeParseExpiry(fromBackend) * 1000;\n }\n if (configExpiry !== undefined) {\n return now + safeParseExpiry(configExpiry) * 1000;\n }\n\n return undefined;\n}\n","import type { AuthConfig, AuthSession, AuthTokens, LoginResponse } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n cookies: {\n get(name: string): { value: string } | undefined;\n };\n};\n\n/**\n * Retrieves and validates the auth session on the server side.\n * Reads the encrypted session cookie, validates token expiry,\n * and refreshes if needed.\n *\n * Compatible with Next.js App Router (NextRequest) and Pages Router (IncomingMessage).\n *\n * @example\n * // app/dashboard/page.tsx\n * import { getServerSession } from \"next-token-auth/server\";\n *\n * export default async function Page({ request }) {\n * const session = await getServerSession(request, config);\n * if (!session.isAuthenticated) redirect(\"/login\");\n * }\n */\nexport async function getServerSession<User = unknown>(\n req: NextRequest,\n config: AuthConfig<User>\n): Promise<AuthSession<User>> {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = req.cookies.get(cookieName)?.value;\n\n if (!cookieValue) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n let tokens: AuthTokens | null = null;\n\n try {\n const json = await decrypt(cookieValue, config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n const now = Date.now();\n const threshold = (config.refreshThreshold ?? 60) * 1000;\n const accessExpired = now >= tokens.accessTokenExpiresAt - threshold;\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n\n // Both expired → clear session\n if (accessExpired && refreshExpired) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n\n // Access expired but refresh valid → attempt server-side refresh\n if (accessExpired && !refreshExpired) {\n const refreshed = await serverRefresh<User>(tokens, config);\n if (!refreshed) {\n return { user: null, tokens: null, isAuthenticated: false };\n }\n tokens = refreshed;\n }\n\n const user = await fetchUser<User>(tokens.accessToken, config);\n\n return {\n user,\n tokens,\n isAuthenticated: true,\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nasync function serverRefresh<User>(\n tokens: AuthTokens,\n config: AuthConfig<User>\n): Promise<AuthTokens | null> {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const refreshPath = config.endpoints.refresh.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${refreshPath}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) return null;\n\n const data = (await res.json()) as LoginResponse<User>;\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(\n data,\n config.expiry?.accessTokenExpiresIn,\n strategy\n ),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(\n data,\n config.expiry?.refreshTokenExpiresIn,\n strategy\n ),\n };\n } catch {\n return null;\n }\n}\n\nasync function fetchUser<User>(\n accessToken: string,\n config: AuthConfig<User>\n): Promise<User | null> {\n if (!config.endpoints.me) return null;\n\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n const mePath = config.endpoints.me.replace(/^\\//, \"\");\n\n const res = await fetchFn(`${baseUrl}/${mePath}`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!res.ok) return null;\n return (await res.json()) as User;\n } catch {\n return null;\n }\n}\n","import type { AuthConfig, AuthSession, AuthTokens } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\n\n/**\n * Reads the session from the cookie store inside a Server Component or layout.\n * Use this in app/layout.tsx to pre-seed AuthProvider and avoid the auth flash.\n *\n * @example\n * // app/layout.tsx\n * import { getLayoutSession } from \"next-token-auth/server\";\n * import { authConfig } from \"@/lib/auth\";\n *\n * export default async function RootLayout({ children }) {\n * const session = await getLayoutSession(authConfig);\n * return (\n * <AuthProvider config={clientConfig} initialSession={session}>\n * {children}\n * </AuthProvider>\n * );\n * }\n */\nexport async function getLayoutSession<User = unknown>(\n config: AuthConfig<User>\n): Promise<AuthSession<User>> {\n const empty: AuthSession<User> = {\n user: null,\n tokens: null,\n isAuthenticated: false,\n };\n\n try {\n const { cookies } = await import(\"next/headers\");\n const cookieStore = await cookies();\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n const raw = cookieStore.get(cookieName)?.value;\n\n if (!raw) return empty;\n\n // Decrypt the cookie using the server-side secret\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return empty;\n }\n\n // Reject if refresh token has expired\n if (tokens.refreshTokenExpiresAt && Date.now() >= tokens.refreshTokenExpiresAt) {\n return empty;\n }\n\n // Fetch user info using the access token\n let user: User | null = null;\n if (config.endpoints.me) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (res.ok) user = (await res.json()) as User;\n } catch {\n // User fetch failed, but token exists — still authenticated\n }\n }\n\n // Return session without exposing raw tokens to the client\n return { user, tokens: null, isAuthenticated: true };\n } catch {\n return empty;\n }\n}\n","import type { AuthConfig, AuthSession } from \"../types\";\nimport { getServerSession } from \"./getServerSession\";\n\ntype NextRequest = {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string };\n};\n\ntype NextResponse = {\n redirect(url: URL): NextResponse;\n next(): NextResponse;\n};\n\ntype RouteHandler<User = unknown> = (\n req: NextRequest,\n session: AuthSession<User>\n) => Promise<Response> | Response;\n\n/**\n * Higher-order function that wraps a Next.js route handler with auth protection.\n * Redirects unauthenticated requests to the login page.\n *\n * @example\n * // app/api/protected/route.ts\n * export const GET = withAuth(config, async (req, session) => {\n * return Response.json({ user: session.user });\n * });\n */\nexport function withAuth<User = unknown>(\n config: AuthConfig<User>,\n handler: RouteHandler<User>,\n options: { redirectTo?: string } = {}\n) {\n return async (req: NextRequest): Promise<Response> => {\n const session = await getServerSession<User>(req, config);\n\n if (!session.isAuthenticated) {\n const redirectTo = options.redirectTo ?? \"/login\";\n const loginUrl = new URL(redirectTo, `https://${req.nextUrl.pathname}`);\n return Response.redirect(loginUrl);\n }\n\n return handler(req, session);\n };\n}\n","import type { AuthConfig } from \"../types\";\nimport { decrypt } from \"../utils/crypto\";\nimport type { AuthTokens } from \"../types\";\n\n/**\n * Next.js middleware factory for route protection.\n *\n * @example\n * // middleware.ts (project root)\n * import { authMiddleware } from \"next-token-auth/server\";\n * import { authConfig } from \"./lib/auth\";\n *\n * export const middleware = authMiddleware(authConfig);\n *\n * export const config = {\n * matcher: [\"/auth/login\", \"/auth/register\", \"/dashboard*\", \"/profile*\"],\n * };\n */\nexport function authMiddleware<User = unknown>(authConfig: AuthConfig<User>) {\n return async function middleware(request: {\n cookies: { get(name: string): { value: string } | undefined };\n nextUrl: { pathname: string; origin: string };\n url: string;\n }): Promise<Response> {\n const { NextResponse } = await import(\"next/server\");\n\n const pathname = request.nextUrl.pathname;\n const cookieName = authConfig.token.cookieName ?? \"next-token-auth.session\";\n const cookieValue = request.cookies.get(cookieName)?.value;\n\n const isAuthenticated = await checkSession(cookieValue, authConfig.secret);\n\n // ── Guest-only routes ────────────────────────────────────────────────────\n // Accessible only when NOT authenticated.\n // Authenticated users are redirected to redirectAuthenticatedTo.\n const guestOnlyRoutes = authConfig.routes?.guestOnly ?? [];\n if (isGuestOnlyRoute(pathname, guestOnlyRoutes)) {\n if (isAuthenticated) {\n const redirectTo = authConfig.routes?.redirectAuthenticatedTo ?? \"/dashboard\";\n return NextResponse.redirect(new URL(redirectTo, request.nextUrl.origin));\n }\n return NextResponse.next();\n }\n\n // ── Public routes ────────────────────────────────────────────────────────\n const publicRoutes = authConfig.routes?.public ?? [];\n if (matchesAny(pathname, publicRoutes)) {\n return NextResponse.next();\n }\n\n // ── Protected routes ─────────────────────────────────────────────────────\n const protectedRoutes = authConfig.routes?.protected ?? [];\n const requiresAuth =\n protectedRoutes.length === 0 || matchesAny(pathname, protectedRoutes);\n\n if (!requiresAuth) {\n return NextResponse.next();\n }\n\n if (!isAuthenticated) {\n // Use the configured login endpoint path, falling back to \"/login\"\n const loginPath = authConfig.routes?.loginPath ?? \"/login\";\n return NextResponse.redirect(new URL(loginPath, request.nextUrl.origin));\n }\n\n return NextResponse.next();\n };\n}\n\n// ─── Session check ────────────────────────────────────────────────────────────\n\nasync function checkSession(\n cookieValue: string | undefined,\n secret: string\n): Promise<boolean> {\n if (!cookieValue) return false;\n\n try {\n const json = await decrypt(cookieValue, secret);\n const tokens = JSON.parse(json) as AuthTokens;\n const now = Date.now();\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? now >= tokens.refreshTokenExpiresAt\n : false;\n return !refreshExpired;\n } catch {\n return false;\n }\n}\n\n// ─── Route matchers ───────────────────────────────────────────────────────────\n\nfunction isGuestOnlyRoute(pathname: string, routes: string[]): boolean {\n return matchesAny(pathname, routes);\n}\n\n/**\n * Matches a pathname against a list of patterns.\n * Supports wildcards: \"/dashboard*\" matches \"/dashboard\", \"/dashboard/\", \"/dashboard/settings\"\n */\nfunction matchesAny(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => matchRoute(pathname, pattern));\n}\n\nfunction matchRoute(pathname: string, pattern: string): boolean {\n if (pattern.endsWith(\"*\")) {\n const base = pattern.slice(0, -1); // e.g. \"/dashboard\"\n // matches \"/dashboard\", \"/dashboard/\", \"/dashboard/anything\"\n return pathname === base || pathname.startsWith(base + \"/\") || pathname.startsWith(base);\n }\n return pathname === pattern;\n}\n","import type { AuthConfig, AuthTokens, LoginResponse } from \"../types\";\nimport { encrypt, decrypt } from \"../utils/crypto\";\nimport {\n resolveAccessTokenExpiry,\n resolveRefreshTokenExpiry,\n} from \"../utils/expiry\";\n\ntype NextRequest = {\n json(): Promise<unknown>;\n cookies: { get(name: string): { value: string } | undefined };\n};\n\n/**\n * Creates Next.js Route Handlers for login, logout, session, and refresh.\n * Mount these at `app/api/auth/[action]/route.ts`.\n *\n * All encryption happens server-side — the secret never leaves the server.\n *\n * @example\n * // app/api/auth/[action]/route.ts\n * import { createAuthHandlers } from \"next-token-auth/server\";\n * import { authConfig } from \"@/lib/auth\";\n *\n * export const { GET, POST } = createAuthHandlers(authConfig);\n */\nexport function createAuthHandlers<User = unknown>(config: AuthConfig<User>) {\n const cookieName = config.token.cookieName ?? \"next-token-auth.session\";\n\n return {\n POST: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/login ─────────────────────────────────────────────────────\n if (action === \"login\") {\n const body = await req.json();\n const fetchFn = config.fetchFn ?? fetch;\n\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.login}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const text = await res.text();\n return NextResponse.json({ error: text }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const tokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(tokens), config.secret);\n const maxAge = tokens.refreshTokenExpiresAt\n ? Math.floor((tokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n // Fetch user from /me endpoint if not included in login response\n let user: User | null = data.user ?? null;\n if (!user && config.endpoints.me) {\n try {\n const meRes = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (meRes.ok) user = (await meRes.json()) as User;\n } catch {\n // User fetch failed — continue without user data\n }\n }\n\n return NextResponse.json(\n { ok: true, user },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n // ── /api/auth/logout ────────────────────────────────────────────────────\n if (action === \"logout\") {\n if (config.endpoints.logout) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n await fetchFn(`${config.baseUrl}${config.endpoints.logout}`, {\n method: \"POST\",\n });\n } catch {\n // Best-effort\n }\n }\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": `${cookieName}=; Max-Age=0; Path=/`,\n },\n }\n );\n }\n\n // ── /api/auth/refresh ───────────────────────────────────────────────────\n if (action === \"refresh\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ error: \"No session\" }, { status: 401 });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ error: \"Invalid session\" }, { status: 401 });\n }\n\n if (tokens.refreshTokenExpiresAt && Date.now() >= tokens.refreshTokenExpiresAt) {\n return NextResponse.json({ error: \"Refresh token expired\" }, { status: 401 });\n }\n\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.refresh}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: tokens.refreshToken }),\n });\n\n if (!res.ok) {\n return NextResponse.json({ error: \"Refresh failed\" }, { status: res.status });\n }\n\n const data = (await res.json()) as LoginResponse<User>;\n const newTokens = buildTokens(data, config);\n\n const encrypted = await encrypt(JSON.stringify(newTokens), config.secret);\n const maxAge = newTokens.refreshTokenExpiresAt\n ? Math.floor((newTokens.refreshTokenExpiresAt - Date.now()) / 1000)\n : 604800;\n\n const secure = config.token.secure !== false ? \"Secure; \" : \"\";\n const sameSite = config.token.sameSite ?? \"lax\";\n\n return NextResponse.json(\n { ok: true },\n {\n headers: {\n \"Set-Cookie\": [\n `${cookieName}=${encodeURIComponent(encrypted)}`,\n `HttpOnly`,\n `Max-Age=${maxAge}`,\n `Path=/`,\n `SameSite=${sameSite}`,\n secure,\n ]\n .filter(Boolean)\n .join(\"; \"),\n },\n }\n );\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n\n GET: async (\n req: NextRequest,\n context: { params: Promise<{ action: string }> | { action: string } }\n ): Promise<Response> => {\n const { NextResponse } = await import(\"next/server\");\n const params = await Promise.resolve(context.params);\n const action = params.action;\n\n // ── /api/auth/session ───────────────────────────────────────────────────\n if (action === \"session\") {\n const raw = req.cookies.get(cookieName)?.value;\n if (!raw) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n let tokens: AuthTokens;\n try {\n const json = await decrypt(decodeURIComponent(raw), config.secret);\n tokens = JSON.parse(json) as AuthTokens;\n } catch {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n const refreshExpired = tokens.refreshTokenExpiresAt\n ? Date.now() >= tokens.refreshTokenExpiresAt\n : false;\n\n if (refreshExpired) {\n return NextResponse.json({ user: null, isAuthenticated: false });\n }\n\n // Fetch user from backend\n let user: User | null = null;\n if (config.endpoints.me) {\n try {\n const fetchFn = config.fetchFn ?? fetch;\n const res = await fetchFn(`${config.baseUrl}${config.endpoints.me}`, {\n headers: { Authorization: `Bearer ${tokens.accessToken}` },\n });\n if (res.ok) user = (await res.json()) as User;\n } catch {\n // User fetch failed — still return authenticated: true if tokens are valid\n }\n }\n\n return NextResponse.json({ user, isAuthenticated: true });\n }\n\n return NextResponse.json({ error: \"Unknown action\" }, { status: 400 });\n },\n };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction buildTokens<User>(\n data: LoginResponse<User>,\n config: AuthConfig<User>\n): AuthTokens {\n const strategy = config.expiry?.strategy ?? \"hybrid\";\n const configAccess = config.expiry?.accessTokenExpiresIn;\n const configRefresh = config.expiry?.refreshTokenExpiresIn;\n\n return {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n accessTokenExpiresAt: resolveAccessTokenExpiry(data, configAccess, strategy),\n refreshTokenExpiresAt: resolveRefreshTokenExpiry(data, configRefresh, strategy),\n };\n}\n"]}
|