@geekapps/auth-nextjs 0.2.8 → 0.2.9
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/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/middleware.js +6 -1
- package/dist/middleware.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/actions.js
CHANGED
|
@@ -88,7 +88,7 @@ async function refreshAndSaveTokens() {
|
|
|
88
88
|
const clientSecret = env("GEEKAPPS_AUTH_CLIENT_SECRET") ?? "";
|
|
89
89
|
if (!refreshToken || !clientId) return null;
|
|
90
90
|
const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
91
|
-
const response = await fetch(`${resolveIssuer()}/auth/
|
|
91
|
+
const response = await fetch(`${resolveIssuer()}/auth/token`, {
|
|
92
92
|
method: "POST",
|
|
93
93
|
headers: {
|
|
94
94
|
"content-type": "application/x-www-form-urlencoded",
|
package/dist/actions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/actions.ts"],"sourcesContent":["\"use server\";\n\nimport { cookies, headers } from \"next/headers\";\nimport type { ConnectedAccount, Organization, User } from \"./client\";\n\n// ── cookie helpers (duplicated from server.ts to keep this file self-contained) ──\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction normalizeBaseUrl(url: string) {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction resolveIssuer() {\n return normalizeBaseUrl(\n env(\"GEEKAPPS_AUTH_ISSUER\") ?? env(\"GEEKAPPS_AUTH_API_URL\") ?? \"http://localhost:3020\",\n );\n}\n\nfunction getServerClientHeaders() {\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\");\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\");\n\n return clientId && clientSecret\n ? {\n \"x-geekapps-client-id\": clientId,\n \"x-geekapps-client-secret\": clientSecret,\n }\n : {};\n}\n\nfunction hashClientId(clientId: string): string {\n let h = 5381;\n for (let i = 0; i < clientId.length; i++) {\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\n h = h >>> 0;\n }\n return h.toString(16).padStart(8, \"0\");\n}\n\nfunction deriveCookiePrefix(): string {\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\") ?? \"\";\n if (!clientId) return \"gk\";\n return `gk_${hashClientId(clientId)}`;\n}\n\ntype SlotMeta = { id: string; sid?: string; n?: string; e?: string; p?: string };\n\nfunction decodeMeta(value: string): SlotMeta | null {\n try {\n const m = JSON.parse(Buffer.from(value, \"base64url\").toString(\"utf8\")) as SlotMeta;\n return m.id ? m : null;\n } catch {\n return null;\n }\n}\n\nasync function getCookieNames() {\n const prefix = deriveCookiePrefix();\n return {\n active: `${prefix}_active`,\n count: `${prefix}_count`,\n activeOrganizationId: `${prefix}_ao`,\n slotMeta: (n: number) => `${prefix}_m${n}`,\n slotAt: (n: number) => `${prefix}_at${n}`,\n slotRt: (n: number) => `${prefix}_rt${n}`,\n };\n}\n\nasync function getActiveAccessToken(): Promise<string | null> {\n // Prefer the token injected by the middleware via request header (same-request refresh)\n try {\n const hdrs = await headers();\n const injected = hdrs.get(\"x-gk-access-token\");\n if (injected) return injected;\n } catch {}\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const raw = cookieStore.get(cn.active)?.value;\n const activeIdx = raw ? Number.parseInt(raw, 10) : 0;\n const countRaw = cookieStore.get(cn.count)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n if (count === 0) return null;\n const idx = activeIdx >= 1 && activeIdx <= count ? activeIdx : 1;\n return cookieStore.get(cn.slotAt(idx))?.value ?? null;\n}\n\nasync function getActiveRefreshToken(): Promise<string | null> {\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const raw = cookieStore.get(cn.active)?.value;\n const activeIdx = raw ? Number.parseInt(raw, 10) : 0;\n const countRaw = cookieStore.get(cn.count)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n if (count === 0) return null;\n const idx = activeIdx >= 1 && activeIdx <= count ? activeIdx : 1;\n return cookieStore.get(cn.slotRt(idx))?.value ?? null;\n}\n\nasync function refreshAndSaveTokens(): Promise<string | null> {\n const refreshToken = await getActiveRefreshToken();\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\") ?? \"\";\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\") ?? \"\";\n if (!refreshToken || !clientId) return null;\n\n const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString(\"base64\");\n const response = await fetch(`${resolveIssuer()}/auth/refresh`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({ grant_type: \"refresh_token\", refresh_token: refreshToken }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return null;\n\n const data = await response.json().catch(() => null) as Record<string, unknown> | null;\n if (!data) return null;\n\n const newAccessToken =\n (data.accessToken ?? data.access_token) as string | undefined;\n const newRefreshToken =\n (data.refreshToken ?? data.refresh_token) as string | undefined;\n\n if (!newAccessToken) return null;\n\n // Update the active slot cookies\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const raw = cookieStore.get(cn.active)?.value;\n const activeIdx = raw ? Number.parseInt(raw, 10) : 1;\n const opts = {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n };\n cookieStore.set(cn.slotAt(activeIdx), newAccessToken, opts);\n if (newRefreshToken) cookieStore.set(cn.slotRt(activeIdx), newRefreshToken, opts);\n // Update public token cookie\n cookieStore.set(`${deriveCookiePrefix()}_tp`, newAccessToken, {\n httpOnly: false,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n });\n\n return newAccessToken;\n}\n\nasync function authFetch<T>(path: string): Promise<T> {\n let accessToken = await getActiveAccessToken();\n if (!accessToken) throw new Error(\"Not authenticated\");\n\n const issuer = resolveIssuer();\n const doFetch = (token: string) =>\n fetch(`${issuer}${path}`, {\n headers: {\n authorization: `Bearer ${token}`,\n ...getServerClientHeaders(),\n } as HeadersInit,\n cache: \"no-store\",\n });\n\n let response = await doFetch(accessToken);\n\n if (response.status === 401) {\n const newToken = await refreshAndSaveTokens();\n if (!newToken) throw new Error(\"Session expired\");\n response = await doFetch(newToken);\n }\n\n if (!response.ok) {\n const err = await response.json().catch(() => null) as Record<string, unknown> | null;\n throw new Error((err?.error_description ?? err?.error ?? err?.message ?? `Auth error ${response.status}`) as string);\n }\n\n if (response.status === 204) return null as T;\n return response.json() as Promise<T>;\n}\n\n// ── Exported server actions ────────────────────────────────────────────────────\n\nexport async function getMe(): Promise<{ user: User | null }> {\n try {\n const data = await authFetch<{ user: User | null } | User | null>(\"/auth/me\");\n if (!data) return { user: null };\n if (typeof data === \"object\" && \"user\" in data) return data as { user: User | null };\n return { user: data as User | null };\n } catch {\n return { user: null };\n }\n}\n\nexport async function getAccounts(): Promise<{ accounts: ConnectedAccount[] }> {\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const countRaw = cookieStore.get(cn.count)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n const activeRaw = cookieStore.get(cn.active)?.value;\n const activeIdx = activeRaw ? Number.parseInt(activeRaw, 10) : 0;\n\n const accounts: ConnectedAccount[] = [];\n for (let i = 1; i <= count; i++) {\n const at = cookieStore.get(cn.slotAt(i))?.value;\n if (!at) continue;\n const meta = decodeMeta(cookieStore.get(cn.slotMeta(i))?.value ?? \"\");\n if (!meta) continue;\n accounts.push({\n id: meta.id,\n sessionId: meta.sid ?? meta.id,\n isActive: i === activeIdx,\n user: {\n id: meta.id,\n name: meta.n ?? null,\n email: meta.e ?? \"\",\n imageUrl: meta.p ?? null,\n phone: null,\n },\n });\n }\n\n return { accounts };\n}\n\nexport async function getOrganizations(): Promise<{ organizations: Organization[]; currentOrgId?: string | null }> {\n try {\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const activeOrgId = cookieStore.get(cn.activeOrganizationId)?.value ?? null;\n const data = await authFetch<Organization[] | { organizations: Organization[] }>(\"/organizations\");\n const organizations = Array.isArray(data) ? data : (data as { organizations: Organization[] }).organizations;\n const resolvedOrgId = activeOrgId ?? organizations[0]?.id ?? null;\n return { organizations, currentOrgId: resolvedOrgId };\n } catch (err) {\n console.error(\"[getOrganizations] error:\", err);\n return { organizations: [] };\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/actions.ts"],"sourcesContent":["\"use server\";\n\nimport { cookies, headers } from \"next/headers\";\nimport type { ConnectedAccount, Organization, User } from \"./client\";\n\n// ── cookie helpers (duplicated from server.ts to keep this file self-contained) ──\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction normalizeBaseUrl(url: string) {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction resolveIssuer() {\n return normalizeBaseUrl(\n env(\"GEEKAPPS_AUTH_ISSUER\") ?? env(\"GEEKAPPS_AUTH_API_URL\") ?? \"http://localhost:3020\",\n );\n}\n\nfunction getServerClientHeaders() {\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\");\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\");\n\n return clientId && clientSecret\n ? {\n \"x-geekapps-client-id\": clientId,\n \"x-geekapps-client-secret\": clientSecret,\n }\n : {};\n}\n\nfunction hashClientId(clientId: string): string {\n let h = 5381;\n for (let i = 0; i < clientId.length; i++) {\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\n h = h >>> 0;\n }\n return h.toString(16).padStart(8, \"0\");\n}\n\nfunction deriveCookiePrefix(): string {\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\") ?? \"\";\n if (!clientId) return \"gk\";\n return `gk_${hashClientId(clientId)}`;\n}\n\ntype SlotMeta = { id: string; sid?: string; n?: string; e?: string; p?: string };\n\nfunction decodeMeta(value: string): SlotMeta | null {\n try {\n const m = JSON.parse(Buffer.from(value, \"base64url\").toString(\"utf8\")) as SlotMeta;\n return m.id ? m : null;\n } catch {\n return null;\n }\n}\n\nasync function getCookieNames() {\n const prefix = deriveCookiePrefix();\n return {\n active: `${prefix}_active`,\n count: `${prefix}_count`,\n activeOrganizationId: `${prefix}_ao`,\n slotMeta: (n: number) => `${prefix}_m${n}`,\n slotAt: (n: number) => `${prefix}_at${n}`,\n slotRt: (n: number) => `${prefix}_rt${n}`,\n };\n}\n\nasync function getActiveAccessToken(): Promise<string | null> {\n // Prefer the token injected by the middleware via request header (same-request refresh)\n try {\n const hdrs = await headers();\n const injected = hdrs.get(\"x-gk-access-token\");\n if (injected) return injected;\n } catch {}\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const raw = cookieStore.get(cn.active)?.value;\n const activeIdx = raw ? Number.parseInt(raw, 10) : 0;\n const countRaw = cookieStore.get(cn.count)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n if (count === 0) return null;\n const idx = activeIdx >= 1 && activeIdx <= count ? activeIdx : 1;\n return cookieStore.get(cn.slotAt(idx))?.value ?? null;\n}\n\nasync function getActiveRefreshToken(): Promise<string | null> {\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const raw = cookieStore.get(cn.active)?.value;\n const activeIdx = raw ? Number.parseInt(raw, 10) : 0;\n const countRaw = cookieStore.get(cn.count)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n if (count === 0) return null;\n const idx = activeIdx >= 1 && activeIdx <= count ? activeIdx : 1;\n return cookieStore.get(cn.slotRt(idx))?.value ?? null;\n}\n\nasync function refreshAndSaveTokens(): Promise<string | null> {\n const refreshToken = await getActiveRefreshToken();\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\") ?? \"\";\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\") ?? \"\";\n if (!refreshToken || !clientId) return null;\n\n const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString(\"base64\");\n const response = await fetch(`${resolveIssuer()}/auth/token`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({ grant_type: \"refresh_token\", refresh_token: refreshToken }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return null;\n\n const data = await response.json().catch(() => null) as Record<string, unknown> | null;\n if (!data) return null;\n\n const newAccessToken =\n (data.accessToken ?? data.access_token) as string | undefined;\n const newRefreshToken =\n (data.refreshToken ?? data.refresh_token) as string | undefined;\n\n if (!newAccessToken) return null;\n\n // Update the active slot cookies\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const raw = cookieStore.get(cn.active)?.value;\n const activeIdx = raw ? Number.parseInt(raw, 10) : 1;\n const opts = {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n };\n cookieStore.set(cn.slotAt(activeIdx), newAccessToken, opts);\n if (newRefreshToken) cookieStore.set(cn.slotRt(activeIdx), newRefreshToken, opts);\n // Update public token cookie\n cookieStore.set(`${deriveCookiePrefix()}_tp`, newAccessToken, {\n httpOnly: false,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n });\n\n return newAccessToken;\n}\n\nasync function authFetch<T>(path: string): Promise<T> {\n let accessToken = await getActiveAccessToken();\n if (!accessToken) throw new Error(\"Not authenticated\");\n\n const issuer = resolveIssuer();\n const doFetch = (token: string) =>\n fetch(`${issuer}${path}`, {\n headers: {\n authorization: `Bearer ${token}`,\n ...getServerClientHeaders(),\n } as HeadersInit,\n cache: \"no-store\",\n });\n\n let response = await doFetch(accessToken);\n\n if (response.status === 401) {\n const newToken = await refreshAndSaveTokens();\n if (!newToken) throw new Error(\"Session expired\");\n response = await doFetch(newToken);\n }\n\n if (!response.ok) {\n const err = await response.json().catch(() => null) as Record<string, unknown> | null;\n throw new Error((err?.error_description ?? err?.error ?? err?.message ?? `Auth error ${response.status}`) as string);\n }\n\n if (response.status === 204) return null as T;\n return response.json() as Promise<T>;\n}\n\n// ── Exported server actions ────────────────────────────────────────────────────\n\nexport async function getMe(): Promise<{ user: User | null }> {\n try {\n const data = await authFetch<{ user: User | null } | User | null>(\"/auth/me\");\n if (!data) return { user: null };\n if (typeof data === \"object\" && \"user\" in data) return data as { user: User | null };\n return { user: data as User | null };\n } catch {\n return { user: null };\n }\n}\n\nexport async function getAccounts(): Promise<{ accounts: ConnectedAccount[] }> {\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const countRaw = cookieStore.get(cn.count)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n const activeRaw = cookieStore.get(cn.active)?.value;\n const activeIdx = activeRaw ? Number.parseInt(activeRaw, 10) : 0;\n\n const accounts: ConnectedAccount[] = [];\n for (let i = 1; i <= count; i++) {\n const at = cookieStore.get(cn.slotAt(i))?.value;\n if (!at) continue;\n const meta = decodeMeta(cookieStore.get(cn.slotMeta(i))?.value ?? \"\");\n if (!meta) continue;\n accounts.push({\n id: meta.id,\n sessionId: meta.sid ?? meta.id,\n isActive: i === activeIdx,\n user: {\n id: meta.id,\n name: meta.n ?? null,\n email: meta.e ?? \"\",\n imageUrl: meta.p ?? null,\n phone: null,\n },\n });\n }\n\n return { accounts };\n}\n\nexport async function getOrganizations(): Promise<{ organizations: Organization[]; currentOrgId?: string | null }> {\n try {\n const cookieStore = await cookies();\n const cn = await getCookieNames();\n const activeOrgId = cookieStore.get(cn.activeOrganizationId)?.value ?? null;\n const data = await authFetch<Organization[] | { organizations: Organization[] }>(\"/organizations\");\n const organizations = Array.isArray(data) ? data : (data as { organizations: Organization[] }).organizations;\n const resolvedOrgId = activeOrgId ?? organizations[0]?.id ?? null;\n return { organizations, currentOrgId: resolvedOrgId };\n } catch (err) {\n console.error(\"[getOrganizations] error:\", err);\n return { organizations: [] };\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/middleware.js
CHANGED
|
@@ -82,6 +82,11 @@ function createAuthMiddleware(input = {}) {
|
|
|
82
82
|
if (Number.isNaN(activeIdx) || activeIdx < 1 || activeIdx > count) {
|
|
83
83
|
activeIdx = count > 0 ? 1 : 0;
|
|
84
84
|
}
|
|
85
|
+
if (activeIdx === 0) {
|
|
86
|
+
const fallbackAt = request.cookies.get(slotAt(1))?.value;
|
|
87
|
+
const fallbackRt = request.cookies.get(slotRt(1))?.value;
|
|
88
|
+
if (fallbackAt || fallbackRt) activeIdx = 1;
|
|
89
|
+
}
|
|
85
90
|
const accessToken = activeIdx > 0 ? request.cookies.get(slotAt(activeIdx))?.value ?? null : null;
|
|
86
91
|
const refreshToken = activeIdx > 0 ? request.cookies.get(slotRt(activeIdx))?.value ?? null : null;
|
|
87
92
|
const origin = resolveAppOrigin(request, input.appUrl);
|
|
@@ -109,7 +114,7 @@ function createAuthMiddleware(input = {}) {
|
|
|
109
114
|
let newRefreshToken = null;
|
|
110
115
|
for (let attempt = 1; attempt <= MAX_REFRESH_ATTEMPTS; attempt++) {
|
|
111
116
|
try {
|
|
112
|
-
const refreshResponse = await fetch(`${issuer}/auth/
|
|
117
|
+
const refreshResponse = await fetch(`${issuer}/auth/token`, {
|
|
113
118
|
method: "POST",
|
|
114
119
|
headers: {
|
|
115
120
|
"content-type": "application/x-www-form-urlencoded",
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse, type NextRequest } from \"next/server\";\nimport { createRemoteJWKSet, jwtVerify } from \"jose\";\n\nexport type AuthMiddlewareConfig = {\n issuer?: string;\n basePath?: string;\n /**\n * @deprecated cookiePrefix is now auto-derived from GEEKAPPS_AUTH_CLIENT_ID.\n * This field is kept for backwards compatibility but is ignored.\n */\n cookiePrefix?: string;\n secureCookies?: boolean;\n cookieDomain?: string;\n /** Base URL of this app (e.g. \"https://meuapp.com\"). Overrides the GEEKAPPS_APP_URL env var. */\n appUrl?: string;\n};\n\ntype TokenLikeResponse = {\n access_token?: string;\n accessToken?: string;\n refresh_token?: string;\n refreshToken?: string;\n id_token?: string;\n idToken?: string;\n};\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction normalizeBaseUrl(url: string) {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeBasePath(path = \"/api/auth\") {\n if (!path.startsWith(\"/\")) return `/${path}`;\n return path.replace(/\\/$/, \"\");\n}\n\nfunction resolveIssuer(input: AuthMiddlewareConfig) {\n return normalizeBaseUrl(\n input.issuer ??\n env(\"GEEKAPPS_AUTH_ISSUER\") ??\n env(\"GEEKAPPS_AUTH_API_URL\") ??\n \"http://localhost:3020\",\n );\n}\n\nfunction hashClientId(clientId: string): string {\n let h = 5381;\n for (let i = 0; i < clientId.length; i++) {\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\n h = h >>> 0;\n }\n return h.toString(16).padStart(8, \"0\");\n}\n\nfunction deriveCookiePrefix(clientId: string | undefined): string {\n if (!clientId) return \"gk\";\n return `gk_${hashClientId(clientId)}`;\n}\n\n\nconst MAX_REFRESH_ATTEMPTS = 3;\n\nfunction decodeJwtExp(token: string): number | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const payload = parts[1]!;\n const padded = payload + \"=\".repeat((4 - (payload.length % 4)) % 4);\n const decoded = JSON.parse(atob(padded)) as { exp?: number };\n return typeof decoded.exp === \"number\" ? decoded.exp : null;\n } catch {\n return null;\n }\n}\n\nfunction resolveAppOrigin(request: NextRequest, appUrl?: string): string {\n const configured =\n appUrl ??\n env(\"GEEKAPPS_APP_URL\");\n if (configured) return configured.replace(/\\/$/, \"\");\n\n throw new Error(\n \"Cannot determine app origin for redirect. Set GEEKAPPS_APP_URL.\",\n );\n}\n\nconst _jwksCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\n\nfunction getRemoteJWKS(issuer: string) {\n if (!_jwksCache.has(issuer)) {\n _jwksCache.set(issuer, createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`)));\n }\n return _jwksCache.get(issuer)!;\n}\n\nasync function verifyAccessToken(token: string, issuer: string): Promise<boolean> {\n try {\n await jwtVerify(token, getRemoteJWKS(issuer), { algorithms: [\"RS256\"], issuer });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function createAuthMiddleware(input: AuthMiddlewareConfig = {}) {\n const issuer = resolveIssuer(input);\n const basePath = normalizeBasePath(input.basePath);\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\");\n const prefix = deriveCookiePrefix(clientId);\n\n const activeCookie = `${prefix}_active`;\n const countCookie = `${prefix}_count`;\n const tokenPubCookie = `${prefix}_tp`; // legacy — cleared on next refresh\n const slotAt = (n: number) => `${prefix}_at${n}`;\n const slotRt = (n: number) => `${prefix}_rt${n}`;\n\n return async function authMiddleware(request: NextRequest): Promise<NextResponse> {\n const countRaw = request.cookies.get(countCookie)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n\n const activeRaw = request.cookies.get(activeCookie)?.value;\n let activeIdx = activeRaw ? Number.parseInt(activeRaw, 10) : 1;\n if (Number.isNaN(activeIdx) || activeIdx < 1 || activeIdx > count) {\n activeIdx = count > 0 ? 1 : 0;\n }\n\n const accessToken = activeIdx > 0 ? (request.cookies.get(slotAt(activeIdx))?.value ?? null) : null;\n const refreshToken = activeIdx > 0 ? (request.cookies.get(slotRt(activeIdx))?.value ?? null) : null;\n\n const origin = resolveAppOrigin(request, input.appUrl);\n const signInUrl = new URL(`${origin}${basePath}/sign-in`);\n const redirectTo = request.nextUrl.pathname + request.nextUrl.search;\n if (redirectTo && redirectTo !== \"/\") {\n signInUrl.searchParams.set(\"redirectTo\", redirectTo);\n }\n\n if (!accessToken && !refreshToken) {\n return NextResponse.redirect(signInUrl);\n }\n\n // Fast-path: check exp before hitting JWKS (avoids network on every request)\n const exp = accessToken ? decodeJwtExp(accessToken) : null;\n const nowSec = Math.floor(Date.now() / 1000);\n const expiredOrMissing = !exp || exp - nowSec < 60;\n\n if (!expiredOrMissing) {\n // Verify signature against app-api JWKS\n const valid = await verifyAccessToken(accessToken!, issuer);\n if (valid) return NextResponse.next();\n }\n\n if (!refreshToken) {\n return NextResponse.redirect(signInUrl);\n }\n\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\") ?? \"\";\n const basicAuth = btoa(`${clientId ?? \"\"}:${clientSecret}`);\n\n let newAccessToken: string | null = null;\n let newRefreshToken: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_REFRESH_ATTEMPTS; attempt++) {\n try {\n const refreshResponse = await fetch(`${issuer}/auth/refresh`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n }),\n cache: \"no-store\",\n });\n\n if (!refreshResponse.ok) break;\n\n const data = (await refreshResponse.json()) as TokenLikeResponse;\n newAccessToken = data.accessToken ?? data.access_token ?? null;\n newRefreshToken = data.refreshToken ?? data.refresh_token ?? null;\n if (newAccessToken) break;\n } catch {\n if (attempt === MAX_REFRESH_ATTEMPTS) break;\n }\n }\n\n if (!newAccessToken) {\n // Refresh failed — clear the active slot and redirect to sign-in\n const response = NextResponse.redirect(signInUrl);\n const clearOpts = {\n httpOnly: true,\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 0,\n };\n response.cookies.set(slotAt(activeIdx), \"\", clearOpts);\n response.cookies.set(slotRt(activeIdx), \"\", clearOpts);\n response.cookies.set(`${prefix}_m${activeIdx}`, \"\", clearOpts);\n response.cookies.set(tokenPubCookie, \"\", { ...clearOpts, httpOnly: false });\n response.cookies.set(activeCookie, \"0\", clearOpts);\n return response;\n }\n\n const cookieOptions = {\n httpOnly: true,\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n ...(input.cookieDomain ? { domain: input.cookieDomain } : {}),\n };\n\n // Forward new token via request header so server actions in the same\n // request can read it — response cookies are not visible within the same request.\n const requestHeaders = new Headers(request.headers);\n requestHeaders.set(\"x-gk-access-token\", newAccessToken);\n\n const response = NextResponse.next({ request: { headers: requestHeaders } });\n response.cookies.set(slotAt(activeIdx), newAccessToken, cookieOptions);\n if (newRefreshToken) response.cookies.set(slotRt(activeIdx), newRefreshToken, cookieOptions);\n // Clear legacy _tp cookie to reduce header size\n if (request.cookies.get(tokenPubCookie)?.value) {\n response.cookies.set(tokenPubCookie, \"\", { httpOnly: false, maxAge: 0, path: \"/\" });\n }\n\n return response;\n };\n}\n"],"mappings":"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","names":["response"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse, type NextRequest } from \"next/server\";\nimport { createRemoteJWKSet, jwtVerify } from \"jose\";\n\nexport type AuthMiddlewareConfig = {\n issuer?: string;\n basePath?: string;\n /**\n * @deprecated cookiePrefix is now auto-derived from GEEKAPPS_AUTH_CLIENT_ID.\n * This field is kept for backwards compatibility but is ignored.\n */\n cookiePrefix?: string;\n secureCookies?: boolean;\n cookieDomain?: string;\n /** Base URL of this app (e.g. \"https://meuapp.com\"). Overrides the GEEKAPPS_APP_URL env var. */\n appUrl?: string;\n};\n\ntype TokenLikeResponse = {\n access_token?: string;\n accessToken?: string;\n refresh_token?: string;\n refreshToken?: string;\n id_token?: string;\n idToken?: string;\n};\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction normalizeBaseUrl(url: string) {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeBasePath(path = \"/api/auth\") {\n if (!path.startsWith(\"/\")) return `/${path}`;\n return path.replace(/\\/$/, \"\");\n}\n\nfunction resolveIssuer(input: AuthMiddlewareConfig) {\n return normalizeBaseUrl(\n input.issuer ??\n env(\"GEEKAPPS_AUTH_ISSUER\") ??\n env(\"GEEKAPPS_AUTH_API_URL\") ??\n \"http://localhost:3020\",\n );\n}\n\nfunction hashClientId(clientId: string): string {\n let h = 5381;\n for (let i = 0; i < clientId.length; i++) {\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\n h = h >>> 0;\n }\n return h.toString(16).padStart(8, \"0\");\n}\n\nfunction deriveCookiePrefix(clientId: string | undefined): string {\n if (!clientId) return \"gk\";\n return `gk_${hashClientId(clientId)}`;\n}\n\n\nconst MAX_REFRESH_ATTEMPTS = 3;\n\nfunction decodeJwtExp(token: string): number | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const payload = parts[1]!;\n const padded = payload + \"=\".repeat((4 - (payload.length % 4)) % 4);\n const decoded = JSON.parse(atob(padded)) as { exp?: number };\n return typeof decoded.exp === \"number\" ? decoded.exp : null;\n } catch {\n return null;\n }\n}\n\nfunction resolveAppOrigin(request: NextRequest, appUrl?: string): string {\n const configured =\n appUrl ??\n env(\"GEEKAPPS_APP_URL\");\n if (configured) return configured.replace(/\\/$/, \"\");\n\n throw new Error(\n \"Cannot determine app origin for redirect. Set GEEKAPPS_APP_URL.\",\n );\n}\n\nconst _jwksCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\n\nfunction getRemoteJWKS(issuer: string) {\n if (!_jwksCache.has(issuer)) {\n _jwksCache.set(issuer, createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`)));\n }\n return _jwksCache.get(issuer)!;\n}\n\nasync function verifyAccessToken(token: string, issuer: string): Promise<boolean> {\n try {\n await jwtVerify(token, getRemoteJWKS(issuer), { algorithms: [\"RS256\"], issuer });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function createAuthMiddleware(input: AuthMiddlewareConfig = {}) {\n const issuer = resolveIssuer(input);\n const basePath = normalizeBasePath(input.basePath);\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\");\n const prefix = deriveCookiePrefix(clientId);\n\n const activeCookie = `${prefix}_active`;\n const countCookie = `${prefix}_count`;\n const tokenPubCookie = `${prefix}_tp`; // legacy — cleared on next refresh\n const slotAt = (n: number) => `${prefix}_at${n}`;\n const slotRt = (n: number) => `${prefix}_rt${n}`;\n\n return async function authMiddleware(request: NextRequest): Promise<NextResponse> {\n const countRaw = request.cookies.get(countCookie)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n\n const activeRaw = request.cookies.get(activeCookie)?.value;\n let activeIdx = activeRaw ? Number.parseInt(activeRaw, 10) : 1;\n if (Number.isNaN(activeIdx) || activeIdx < 1 || activeIdx > count) {\n activeIdx = count > 0 ? 1 : 0;\n }\n\n // Fallback: if count cookie is missing/zero but slot 1 tokens exist, use slot 1.\n // This handles the case where the count/active control cookies expired before the token cookies.\n if (activeIdx === 0) {\n const fallbackAt = request.cookies.get(slotAt(1))?.value;\n const fallbackRt = request.cookies.get(slotRt(1))?.value;\n if (fallbackAt || fallbackRt) activeIdx = 1;\n }\n\n const accessToken = activeIdx > 0 ? (request.cookies.get(slotAt(activeIdx))?.value ?? null) : null;\n const refreshToken = activeIdx > 0 ? (request.cookies.get(slotRt(activeIdx))?.value ?? null) : null;\n\n const origin = resolveAppOrigin(request, input.appUrl);\n const signInUrl = new URL(`${origin}${basePath}/sign-in`);\n const redirectTo = request.nextUrl.pathname + request.nextUrl.search;\n if (redirectTo && redirectTo !== \"/\") {\n signInUrl.searchParams.set(\"redirectTo\", redirectTo);\n }\n\n if (!accessToken && !refreshToken) {\n return NextResponse.redirect(signInUrl);\n }\n\n // Fast-path: check exp before hitting JWKS (avoids network on every request)\n const exp = accessToken ? decodeJwtExp(accessToken) : null;\n const nowSec = Math.floor(Date.now() / 1000);\n const expiredOrMissing = !exp || exp - nowSec < 60;\n\n if (!expiredOrMissing) {\n // Verify signature against app-api JWKS\n const valid = await verifyAccessToken(accessToken!, issuer);\n if (valid) return NextResponse.next();\n }\n\n if (!refreshToken) {\n return NextResponse.redirect(signInUrl);\n }\n\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\") ?? \"\";\n const basicAuth = btoa(`${clientId ?? \"\"}:${clientSecret}`);\n\n let newAccessToken: string | null = null;\n let newRefreshToken: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_REFRESH_ATTEMPTS; attempt++) {\n try {\n const refreshResponse = await fetch(`${issuer}/auth/token`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n }),\n cache: \"no-store\",\n });\n\n if (!refreshResponse.ok) break;\n\n const data = (await refreshResponse.json()) as TokenLikeResponse;\n newAccessToken = data.accessToken ?? data.access_token ?? null;\n newRefreshToken = data.refreshToken ?? data.refresh_token ?? null;\n if (newAccessToken) break;\n } catch {\n if (attempt === MAX_REFRESH_ATTEMPTS) break;\n }\n }\n\n if (!newAccessToken) {\n // Refresh failed — clear the active slot and redirect to sign-in\n const response = NextResponse.redirect(signInUrl);\n const clearOpts = {\n httpOnly: true,\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 0,\n };\n response.cookies.set(slotAt(activeIdx), \"\", clearOpts);\n response.cookies.set(slotRt(activeIdx), \"\", clearOpts);\n response.cookies.set(`${prefix}_m${activeIdx}`, \"\", clearOpts);\n response.cookies.set(tokenPubCookie, \"\", { ...clearOpts, httpOnly: false });\n response.cookies.set(activeCookie, \"0\", clearOpts);\n return response;\n }\n\n const cookieOptions = {\n httpOnly: true,\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n ...(input.cookieDomain ? { domain: input.cookieDomain } : {}),\n };\n\n // Forward new token via request header so server actions in the same\n // request can read it — response cookies are not visible within the same request.\n const requestHeaders = new Headers(request.headers);\n requestHeaders.set(\"x-gk-access-token\", newAccessToken);\n\n const response = NextResponse.next({ request: { headers: requestHeaders } });\n response.cookies.set(slotAt(activeIdx), newAccessToken, cookieOptions);\n if (newRefreshToken) response.cookies.set(slotRt(activeIdx), newRefreshToken, cookieOptions);\n // Clear legacy _tp cookie to reduce header size\n if (request.cookies.get(tokenPubCookie)?.value) {\n response.cookies.set(tokenPubCookie, \"\", { httpOnly: false, maxAge: 0, path: \"/\" });\n }\n\n return response;\n };\n}\n"],"mappings":"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","names":["response"]}
|
package/dist/server.js
CHANGED
|
@@ -385,7 +385,7 @@ function configureGeekappsAuth(input = {}) {
|
|
|
385
385
|
const refreshToken = await getRefreshToken();
|
|
386
386
|
if (!refreshToken || !config.clientId) return null;
|
|
387
387
|
const basicAuth = Buffer.from(`${config.clientId}:${config.clientSecret ?? ""}`).toString("base64");
|
|
388
|
-
const response = await fetch(createUrl(config.issuer, "/auth/
|
|
388
|
+
const response = await fetch(createUrl(config.issuer, "/auth/token"), {
|
|
389
389
|
method: "POST",
|
|
390
390
|
headers: {
|
|
391
391
|
"content-type": "application/x-www-form-urlencoded",
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import { cookies, headers } from \"next/headers\";\nimport { redirect } from \"next/navigation\";\nimport { NextResponse, type NextRequest } from \"next/server\";\nimport { createRemoteJWKSet, jwtVerify, type JWTPayload } from \"jose\";\n\nexport type GeekappsAuthConfig = {\n /**\n * Auth API/issuer URL. Optional when GEEKAPPS_AUTH_ISSUER or\n * GEEKAPPS_AUTH_API_URL is defined.\n */\n issuer?: string;\n\n /**\n * OAuth client id. Optional when GEEKAPPS_AUTH_CLIENT_ID is defined.\n */\n clientId?: string;\n\n /**\n * OAuth client secret for confidential clients. Optional when\n * GEEKAPPS_AUTH_CLIENT_SECRET is defined.\n */\n clientSecret?: string;\n\n /**\n * Callback URL. Optional when GEEKAPPS_AUTH_REDIRECT_URI is defined.\n * If omitted, it is inferred from the current request origin + basePath/callback.\n */\n redirectUri?: string;\n\n scopes?: string[];\n basePath?: string;\n /**\n * @deprecated cookiePrefix is now auto-derived from clientId.\n * This field is kept for backwards compatibility but is ignored.\n */\n cookiePrefix?: string;\n cookieDomain?: string;\n secureCookies?: boolean;\n\n /**\n * Friendly alias used by apps. Same as afterSignInRedirectTo.\n */\n redirectTo?: string;\n\n afterSignInRedirectTo?: string;\n afterSignOutRedirectTo?: string;\n};\n\ntype ResolvedGeekappsAuthConfig = GeekappsAuthConfig & {\n issuer: string;\n clientId: string;\n basePath: string;\n cookiePrefix: string;\n};\n\nexport type SessionTokens = {\n accessToken: string | null;\n refreshToken: string | null;\n idToken: string | null;\n sessionId: string | null;\n};\n\nexport type StoredAccount = {\n /** Stable identifier — `sub` from id_token or fallback to sessionId. */\n id: string;\n accessToken: string;\n refreshToken: string | null;\n idToken: string | null;\n sessionId: string | null;\n user: {\n sub: string;\n name?: string | null;\n email?: string | null;\n picture?: string | null;\n phone?: string | null;\n };\n};\n\nexport type ServerAuthApiClient = {\n get: <T>(path: string) => Promise<T>;\n post: <T>(path: string, body?: unknown) => Promise<T>;\n patch: <T>(path: string, body?: unknown) => Promise<T>;\n put: <T>(path: string, body?: unknown) => Promise<T>;\n delete: <T>(path: string) => Promise<T>;\n};\n\ntype JsonObject = Record<string, unknown>;\n\ntype TokenLikeResponse = JsonObject & {\n access_token?: string;\n accessToken?: string;\n refresh_token?: string;\n refreshToken?: string;\n id_token?: string;\n idToken?: string;\n session_id?: string;\n sessionId?: string;\n tokens?: {\n access_token?: string;\n accessToken?: string;\n refresh_token?: string;\n refreshToken?: string;\n id_token?: string;\n idToken?: string;\n session_id?: string;\n sessionId?: string;\n };\n};\n\nconst MAX_ACCOUNTS = 8;\n\nfunction normalizeBaseUrl(url: string) {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeBasePath(path = \"/api/auth\") {\n if (!path.startsWith(\"/\")) return `/${path}`;\n return path.replace(/\\/$/, \"\");\n}\n\nfunction createUrl(baseUrl: string, path: string) {\n if (/^https?:\\/\\//.test(path)) return path;\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${normalizeBaseUrl(baseUrl)}${normalizedPath}`;\n}\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction resolveIssuer(input: GeekappsAuthConfig) {\n return normalizeBaseUrl(\n input.issuer ??\n env(\"GEEKAPPS_AUTH_ISSUER\") ??\n env(\"GEEKAPPS_AUTH_API_URL\") ??\n \"http://localhost:3020\",\n );\n}\n\nfunction resolveClientId(input: GeekappsAuthConfig) {\n return input.clientId ?? env(\"GEEKAPPS_AUTH_CLIENT_ID\") ?? \"\";\n}\n\nfunction resolveClientSecret(input: GeekappsAuthConfig) {\n return input.clientSecret ?? env(\"GEEKAPPS_AUTH_CLIENT_SECRET\");\n}\n\nfunction applyClientCredentials(url: URL, config: ResolvedGeekappsAuthConfig) {\n if (!config.clientId || !config.clientSecret) return;\n url.searchParams.set(\"client_id\", config.clientId);\n url.searchParams.set(\"client_secret\", config.clientSecret);\n}\n\nfunction resolveConfiguredRedirectUri(input: GeekappsAuthConfig) {\n return input.redirectUri ?? env(\"GEEKAPPS_AUTH_REDIRECT_URI\");\n}\n\n/**\n * Derives a short stable 8-char hex hash from a clientId string.\n * Uses a simple djb2-style hash — no crypto dependency needed.\n */\nfunction hashClientId(clientId: string): string {\n let h = 5381;\n for (let i = 0; i < clientId.length; i++) {\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\n h = h >>> 0; // keep unsigned 32-bit\n }\n return h.toString(16).padStart(8, \"0\");\n}\n\n/**\n * Auto-derives the cookie prefix from clientId.\n * Format: `gk_{8-char-hash}` — guaranteed unique per OAuth client.\n * Falls back to `gk` when clientId is empty (dev/test environments).\n */\nfunction deriveCookiePrefix(clientId: string): string {\n if (!clientId) return \"gk\";\n return `gk_${hashClientId(clientId)}`;\n}\n\nfunction requestOrigin(request: NextRequest) {\n const configured = env(\"GEEKAPPS_APP_URL\");\n if (configured) return configured.replace(/\\/$/, \"\");\n\n throw new Error(\n \"Cannot determine app origin. Set GEEKAPPS_APP_URL.\",\n );\n}\n\nfunction resolveRedirectUri(config: ResolvedGeekappsAuthConfig, request: NextRequest) {\n return config.redirectUri ?? `${requestOrigin(request)}${config.basePath}/callback`;\n}\n\nfunction tokenFromResponse(data: TokenLikeResponse): SessionTokens {\n return {\n accessToken: data.accessToken ?? data.access_token ?? data.tokens?.accessToken ?? data.tokens?.access_token ?? null,\n refreshToken:\n data.refreshToken ?? data.refresh_token ?? data.tokens?.refreshToken ?? data.tokens?.refresh_token ?? null,\n idToken: data.idToken ?? data.id_token ?? data.tokens?.idToken ?? data.tokens?.id_token ?? null,\n sessionId: data.sessionId ?? data.session_id ?? data.tokens?.sessionId ?? data.tokens?.session_id ?? null,\n };\n}\n\n/** Decode a JWT payload without verifying signature (safe for client-visible claims). */\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length < 2) return null;\n const payload = parts[1];\n if (!payload) return null;\n return JSON.parse(Buffer.from(payload, \"base64url\").toString(\"utf8\")) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction parseAccountFromJwt(tokens: SessionTokens): StoredAccount | null {\n if (!tokens.accessToken) return null;\n\n const jwtToParse = tokens.idToken ?? tokens.accessToken;\n const payload = decodeJwtPayload(jwtToParse);\n if (!payload) return null;\n\n const sub = typeof payload.sub === \"string\" ? payload.sub : null;\n const id = sub ?? tokens.sessionId;\n if (!id) return null;\n\n return {\n id,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n idToken: tokens.idToken ?? null,\n sessionId: tokens.sessionId,\n user: {\n sub: id,\n name: typeof payload.name === \"string\" ? payload.name : null,\n email: typeof payload.email === \"string\" ? payload.email : null,\n picture: typeof payload.picture === \"string\" ? payload.picture : null,\n phone: typeof payload.phone_number === \"string\" ? payload.phone_number : null,\n },\n };\n}\n\n/**\n * Cookie name scheme — 3 cookies per slot, each well under 4096 bytes:\n *\n * {prefix}_m{n} — metadata blob (base64url JSON): { id, sid?, n?, e?, p? }\n * Claims extracted from id_token at login. Never stores tokens.\n * {prefix}_at{n} — access token (httpOnly). ~1-2 KB.\n * {prefix}_rt{n} — refresh token (httpOnly). ~1 KB.\n * {prefix}_active — active slot index (\"1\", \"2\", …)\n * {prefix}_count — total stored slots\n * {prefix}_ao — active org id for this app\n * {prefix}_tp — non-httpOnly copy of active access token for client-side axios\n *\n * id_token is NOT stored in cookies — claims are extracted at login and cached in\n * the metadata cookie. This is the key size saving.\n */\nfunction getCookieNames(prefix: string) {\n return {\n active: `${prefix}_active`,\n count: `${prefix}_count`,\n activeOrganizationId: `${prefix}_ao`,\n tokenPub: `${prefix}_tp`,\n slotMeta: (n: number) => `${prefix}_m${n}`,\n slotAt: (n: number) => `${prefix}_at${n}`,\n slotRt: (n: number) => `${prefix}_rt${n}`,\n };\n}\n\ntype SlotMeta = {\n id: string;\n sid?: string;\n n?: string;\n e?: string;\n p?: string;\n};\n\nfunction encodeMeta(account: StoredAccount): string {\n const m: SlotMeta = { id: account.id };\n if (account.sessionId) m.sid = account.sessionId;\n if (account.user.name) m.n = account.user.name;\n if (account.user.email) m.e = account.user.email;\n if (account.user.picture) m.p = account.user.picture;\n return Buffer.from(JSON.stringify(m), \"utf8\").toString(\"base64url\");\n}\n\nfunction decodeMeta(value: string): SlotMeta | null {\n try {\n const m = JSON.parse(Buffer.from(value, \"base64url\").toString(\"utf8\")) as SlotMeta;\n return m.id ? m : null;\n } catch {\n return null;\n }\n}\n\nfunction getCookieOptions(config: ResolvedGeekappsAuthConfig) {\n return {\n httpOnly: true,\n secure: config.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n ...(config.cookieDomain ? { domain: config.cookieDomain } : {}),\n };\n}\n\nasync function readBody(request: NextRequest) {\n const text = await request.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction appendSearchParams(url: string, request: NextRequest) {\n const target = new URL(url);\n request.nextUrl.searchParams.forEach((value, key) => {\n target.searchParams.set(key, value);\n });\n return target.toString();\n}\n\nfunction routeFromRequest(request: NextRequest, basePath: string) {\n const pathname = request.nextUrl.pathname;\n if (!pathname.startsWith(basePath)) return pathname;\n const route = pathname.slice(basePath.length);\n return route || \"/\";\n}\n\nfunction isJsonResponse(response: Response) {\n return response.headers.get(\"content-type\")?.includes(\"application/json\");\n}\n\nasync function responseFromApi(response: Response) {\n if (response.status === 204) return new NextResponse(null, { status: 204 });\n const body = isJsonResponse(response) ? await response.json().catch(() => null) : await response.text();\n return NextResponse.json(body, { status: response.status });\n}\n\nconst _remoteJWKSCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\n\nfunction getRemoteJWKS(issuer: string) {\n if (!_remoteJWKSCache.has(issuer)) {\n _remoteJWKSCache.set(issuer, createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`)));\n }\n return _remoteJWKSCache.get(issuer)!;\n}\n\nexport async function verifyToken(\n token: string,\n issuer: string,\n): Promise<JWTPayload | null> {\n try {\n const { payload } = await jwtVerify(token, getRemoteJWKS(issuer), {\n algorithms: [\"RS256\"],\n issuer,\n });\n return payload;\n } catch {\n return null;\n }\n}\n\nexport function configureGeekappsAuth(input: GeekappsAuthConfig = {}) {\n const clientId = resolveClientId(input);\n const config: ResolvedGeekappsAuthConfig = {\n ...input,\n issuer: resolveIssuer(input),\n clientId,\n clientSecret: resolveClientSecret(input),\n redirectUri: resolveConfiguredRedirectUri(input),\n afterSignInRedirectTo:\n input.afterSignInRedirectTo ?? input.redirectTo ?? \"/\",\n basePath: normalizeBasePath(input.basePath),\n cookiePrefix: deriveCookiePrefix(clientId),\n };\n\n const cn = getCookieNames(config.cookiePrefix);\n\n // ── Slot helpers ──────────────────────────────────────────────────────────\n\n async function getCount(): Promise<number> {\n const cookieStore = await cookies();\n const raw = cookieStore.get(cn.count)?.value;\n const n = raw ? Number.parseInt(raw, 10) : 0;\n return Number.isNaN(n) ? 0 : n;\n }\n\n async function getActiveIndex(): Promise<number> {\n const cookieStore = await cookies();\n const raw = cookieStore.get(cn.active)?.value;\n if (!raw) return 0;\n const n = Number.parseInt(raw, 10);\n return Number.isNaN(n) ? 0 : n;\n }\n\n function readSlot(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n n: number,\n ): StoredAccount | null {\n const at = cookieStore.get(cn.slotAt(n))?.value;\n if (!at) return null;\n const meta = decodeMeta(cookieStore.get(cn.slotMeta(n))?.value ?? \"\");\n if (!meta) return null;\n return {\n id: meta.id,\n accessToken: at,\n refreshToken: cookieStore.get(cn.slotRt(n))?.value ?? null,\n idToken: null, // not stored in cookies; claims are in meta\n sessionId: meta.sid ?? null,\n user: {\n sub: meta.id,\n name: meta.n ?? null,\n email: meta.e ?? null,\n picture: meta.p ?? null,\n },\n };\n }\n\n function writeSlot(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n n: number,\n account: StoredAccount,\n ) {\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n cookieStore.set(cn.slotMeta(n), encodeMeta(account), opts);\n cookieStore.set(cn.slotAt(n), account.accessToken, opts);\n if (account.refreshToken) cookieStore.set(cn.slotRt(n), account.refreshToken, opts);\n }\n\n function clearSlot(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n n: number,\n ) {\n const clear = { ...getCookieOptions(config), maxAge: 0 };\n cookieStore.set(cn.slotMeta(n), \"\", clear);\n cookieStore.set(cn.slotAt(n), \"\", clear);\n cookieStore.set(cn.slotRt(n), \"\", clear);\n }\n\n // ── Public account helpers ─────────────────────────────────────────────────\n\n async function getAccountsList(): Promise<StoredAccount[]> {\n const [cookieStore, count] = await Promise.all([cookies(), getCount()]);\n const accounts: StoredAccount[] = [];\n for (let i = 1; i <= count; i++) {\n const slot = readSlot(cookieStore, i);\n if (slot) accounts.push(slot);\n }\n return accounts;\n }\n\n async function getActiveAccount(): Promise<StoredAccount | null> {\n const [cookieStore, activeIdx, count] = await Promise.all([cookies(), getActiveIndex(), getCount()]);\n if (count === 0) return null;\n if (activeIdx >= 1 && activeIdx <= count) {\n const slot = readSlot(cookieStore, activeIdx);\n if (slot) return slot;\n }\n // Fall back to slot 1\n return readSlot(cookieStore, 1);\n }\n\n async function getAccessToken() {\n // Prefer the token injected by the middleware via request header (same-request refresh)\n try {\n const hdrs = await headers();\n const injected = hdrs.get(\"x-gk-access-token\");\n if (injected) return injected;\n } catch {}\n const active = await getActiveAccount();\n return active?.accessToken ?? null;\n }\n\n async function getRefreshToken() {\n const active = await getActiveAccount();\n return active?.refreshToken ?? null;\n }\n\n async function getSession(): Promise<SessionTokens | null> {\n const active = await getActiveAccount();\n if (!active) return null;\n return {\n accessToken: active.accessToken,\n refreshToken: active.refreshToken,\n idToken: active.idToken,\n sessionId: active.sessionId,\n };\n }\n\n async function getUser(): Promise<StoredAccount[\"user\"] | null> {\n const active = await getActiveAccount();\n return active?.user ?? null;\n }\n\n async function getOrganizations(): Promise<{ organizations: unknown[]; currentOrgId: string | null }> {\n const cookieStore = await cookies();\n const currentOrgId = cookieStore.get(cn.activeOrganizationId)?.value ?? null;\n try {\n const data = await apiRequest<unknown[] | { organizations: unknown[] }>(\"/organizations\");\n const organizations = Array.isArray(data) ? data : (data as { organizations: unknown[] }).organizations;\n return { organizations, currentOrgId };\n } catch {\n return { organizations: [], currentOrgId };\n }\n }\n\n function clearPublicTokenCookie(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n ) {\n // Clear legacy _tp cookie if present\n if (cookieStore.get(cn.tokenPub)?.value) {\n cookieStore.set(cn.tokenPub, \"\", { httpOnly: false, maxAge: 0, path: \"/\" });\n }\n }\n\n async function saveAccountToList(tokens: SessionTokens) {\n const account = parseAccountFromJwt(tokens);\n if (!account) return;\n\n const cookieStore = await cookies();\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n const count = await getCount();\n\n // Find existing slot for this account id\n let targetSlot = 0;\n for (let i = 1; i <= count; i++) {\n const existing = readSlot(cookieStore, i);\n if (existing?.id === account.id) {\n targetSlot = i;\n break;\n }\n }\n\n if (targetSlot === 0) {\n if (count >= MAX_ACCOUNTS) return;\n targetSlot = count + 1;\n cookieStore.set(cn.count, String(targetSlot), opts);\n }\n\n writeSlot(cookieStore, targetSlot, account);\n cookieStore.set(cn.active, String(targetSlot), opts);\n clearPublicTokenCookie(cookieStore);\n }\n\n // Alias for backwards compat\n const setSessionCookies = saveAccountToList;\n\n async function switchAccount(accountId: string): Promise<boolean> {\n const [cookieStore, count] = await Promise.all([cookies(), getCount()]);\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n\n for (let i = 1; i <= count; i++) {\n const slot = readSlot(cookieStore, i);\n if (slot && (slot.id === accountId || slot.sessionId === accountId)) {\n cookieStore.set(cn.active, String(i), opts);\n clearPublicTokenCookie(cookieStore);\n return true;\n }\n }\n return false;\n }\n\n async function removeActiveAccount() {\n const [cookieStore, activeIdx, count] = await Promise.all([cookies(), getActiveIndex(), getCount()]);\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n const clear = { ...getCookieOptions(config), maxAge: 0 };\n\n if (count === 0) return;\n\n const remaining: StoredAccount[] = [];\n for (let i = 1; i <= count; i++) {\n if (i === activeIdx) continue;\n const slot = readSlot(cookieStore, i);\n if (slot) remaining.push(slot);\n }\n\n for (let i = 1; i <= count; i++) {\n clearSlot(cookieStore, i);\n }\n\n if (remaining.length === 0) {\n cookieStore.set(cn.count, \"0\", clear);\n cookieStore.set(cn.active, \"0\", clear);\n await clearPublicTokenCookie(cookieStore);\n return;\n }\n\n // Re-compact remaining accounts into slots 1..n\n for (let i = 0; i < remaining.length; i++) {\n await writeSlot(cookieStore, i + 1, remaining[i]!);\n }\n cookieStore.set(cn.count, String(remaining.length), opts);\n cookieStore.set(cn.active, \"1\", opts);\n clearPublicTokenCookie(cookieStore);\n }\n\n async function clearAllSessionCookies() {\n const [cookieStore, count] = await Promise.all([cookies(), getCount()]);\n const clear = { ...getCookieOptions(config), maxAge: 0 };\n for (let i = 1; i <= count; i++) {\n clearSlot(cookieStore, i);\n }\n cookieStore.set(cn.count, \"0\", clear);\n cookieStore.set(cn.active, \"0\", clear);\n clearPublicTokenCookie(cookieStore);\n }\n\n async function tryRefreshTokens(): Promise<string | null> {\n const refreshToken = await getRefreshToken();\n if (!refreshToken || !config.clientId) return null;\n\n const basicAuth = Buffer.from(`${config.clientId}:${config.clientSecret ?? \"\"}`).toString(\"base64\");\n\n const response = await fetch(createUrl(config.issuer, \"/auth/refresh\"), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return null;\n\n const data = (await response.json().catch(() => null)) as TokenLikeResponse | null;\n if (!data) return null;\n\n const tokens = tokenFromResponse(data);\n if (!tokens.accessToken) return null;\n\n await saveAccountToList(tokens);\n return tokens.accessToken;\n }\n\n async function apiRequest<T>(path: string, init: RequestInit = {}): Promise<T> {\n const accessToken = await getAccessToken();\n const requestHeaders = new Headers(init.headers);\n\n if (accessToken) requestHeaders.set(\"authorization\", `Bearer ${accessToken}`);\n if (init.body !== undefined && !requestHeaders.has(\"content-type\")) {\n requestHeaders.set(\"content-type\", \"application/json\");\n }\n\n const url = new URL(createUrl(config.issuer, path));\n applyClientCredentials(url, config);\n\n const response = await fetch(url, {\n ...init,\n headers: requestHeaders,\n cache: \"no-store\",\n });\n\n if (response.status === 401) {\n const newAccessToken = await tryRefreshTokens();\n if (newAccessToken) {\n const retryHeaders = new Headers(init.headers);\n retryHeaders.set(\"authorization\", `Bearer ${newAccessToken}`);\n if (init.body !== undefined && !retryHeaders.has(\"content-type\")) {\n retryHeaders.set(\"content-type\", \"application/json\");\n }\n const retryUrl = new URL(createUrl(config.issuer, path));\n applyClientCredentials(retryUrl, config);\n const retryResponse = await fetch(retryUrl, {\n ...init,\n headers: retryHeaders,\n cache: \"no-store\",\n });\n if (!retryResponse.ok) {\n const error = await retryResponse.json().catch(() => null);\n throw new Error(error?.error_description ?? error?.error ?? error?.message ?? `Auth API error ${retryResponse.status}`);\n }\n if (retryResponse.status === 204) return null as T;\n return (await retryResponse.json()) as T;\n }\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => null);\n throw new Error(error?.error_description ?? error?.error ?? error?.message ?? `Auth API error ${response.status}`);\n }\n\n if (response.status === 204) return null as T;\n return (await response.json()) as T;\n }\n\n function createApiClient(): ServerAuthApiClient {\n return {\n get: (path) => apiRequest(path),\n post: (path, body) => apiRequest(path, { method: \"POST\", body: body === undefined ? undefined : JSON.stringify(body) }),\n patch: (path, body) => apiRequest(path, { method: \"PATCH\", body: body === undefined ? undefined : JSON.stringify(body) }),\n put: (path, body) => apiRequest(path, { method: \"PUT\", body: body === undefined ? undefined : JSON.stringify(body) }),\n delete: (path) => apiRequest(path, { method: \"DELETE\" }),\n };\n }\n\n async function requireUser(options: { redirectTo?: string } = {}) {\n const accessToken = await getAccessToken();\n if (!accessToken) {\n redirect(options.redirectTo ?? \"/\");\n }\n return accessToken;\n }\n\n async function createAuthorizeRedirect(request: NextRequest, mode: \"login\" | \"register\" | \"add-account\" | \"google\") {\n const redirectTo = request.nextUrl.searchParams.get(\"redirectTo\") ?? config.afterSignInRedirectTo ?? \"/\";\n const flowId = request.nextUrl.searchParams.get(\"flow_id\");\n const url = new URL(createUrl(config.issuer, mode === \"google\" ? \"/auth/google\" : \"/authorize\"));\n\n if (!config.clientId) {\n return NextResponse.json(\n { error: \"missing_client_id\", message: \"Missing GEEKAPPS_AUTH_CLIENT_ID or clientId.\" },\n { status: 500 },\n );\n }\n\n url.searchParams.set(\"client_id\", config.clientId);\n url.searchParams.set(\"redirect_uri\", resolveRedirectUri(config, request));\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"scope\", (config.scopes ?? [\"openid\", \"profile\", \"email\"]).join(\" \"));\n url.searchParams.set(\"state\", Buffer.from(JSON.stringify({ redirectTo, mode })).toString(\"base64url\"));\n if (mode === \"register\") url.searchParams.set(\"screen_hint\", \"signup\");\n if (mode === \"add-account\") url.searchParams.set(\"prompt\", \"login\");\n if (flowId) url.searchParams.set(\"flow_id\", flowId);\n\n if (mode === \"login\") {\n url.searchParams.set(\"prompt\", \"login\");\n }\n\n return NextResponse.redirect(url);\n }\n\n async function exchangeCode(request: NextRequest) {\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!code) return NextResponse.redirect(new URL(\"/error?error=missing_code\", requestOrigin(request)));\n\n if (!config.clientId) {\n return NextResponse.json(\n { error: \"missing_client_id\", message: \"Missing GEEKAPPS_AUTH_CLIENT_ID or clientId.\" },\n { status: 500 },\n );\n }\n\n const basicAuth = Buffer.from(\n `${config.clientId}:${config.clientSecret ?? \"\"}`,\n ).toString(\"base64\");\n\n const response = await fetch(createUrl(config.issuer, \"/auth/token\"), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n redirect_uri: resolveRedirectUri(config, request),\n }),\n cache: \"no-store\",\n });\n\n const data = (await response.json().catch(() => ({}))) as TokenLikeResponse;\n if (!response.ok) {\n return NextResponse.json(data, { status: response.status });\n }\n\n await saveAccountToList(tokenFromResponse(data));\n\n let redirectTo = config.afterSignInRedirectTo ?? \"/\";\n if (state) {\n try {\n const parsed = JSON.parse(Buffer.from(state, \"base64url\").toString(\"utf8\")) as { redirectTo?: string };\n redirectTo = parsed.redirectTo ?? redirectTo;\n } catch {\n // ignore malformed state\n }\n }\n\n return NextResponse.redirect(new URL(redirectTo, requestOrigin(request)));\n }\n\n function mapLocalPathToApiPath(route: string) {\n if (route === \"/me\") return \"/auth/me\";\n if (route === \"/accounts/switch\") return \"/auth/accounts/switch\";\n if (route === \"/organizations/active\") return \"/auth/organizations/active\";\n if (route === \"/permissions/check\") return \"/auth/permissions/check\";\n if (route === \"/login/password\") return \"/auth/login/password\";\n if (route === \"/register/password\") return \"/auth/register/password\";\n if (route === \"/passwordless/link\") return \"/auth/passwordless/link\";\n return route;\n }\n\n async function handleAccountsLocal(): Promise<NextResponse> {\n const [accounts, activeIdx] = await Promise.all([getAccountsList(), getActiveIndex()]);\n\n return NextResponse.json({\n accounts: accounts.map((a, i) => ({\n id: a.id,\n sessionId: a.sessionId ?? a.id,\n isActive: i + 1 === activeIdx,\n user: {\n id: a.user.sub,\n name: a.user.name ?? null,\n email: a.user.email ?? null,\n imageUrl: a.user.picture ?? null,\n phone: a.user.phone ?? null,\n },\n })),\n });\n }\n\n async function handleOrganizationsLocal(): Promise<NextResponse> {\n const cookieStore = await cookies();\n const activeOrgId = cookieStore.get(cn.activeOrganizationId)?.value ?? null;\n try {\n const data = await apiRequest<unknown[]|{ organizations: unknown[] }>(\"/organizations\");\n const organizations = Array.isArray(data) ? data : (data as { organizations: unknown[] }).organizations;\n return NextResponse.json({ organizations, currentOrgId: activeOrgId });\n } catch {\n return NextResponse.json({ organizations: [], currentOrgId: activeOrgId });\n }\n }\n\n async function handleSwitchAccountLocal(request: NextRequest): Promise<NextResponse> {\n const body = await readBody(request);\n const targetId =\n body && typeof body === \"object\"\n ? String(\n (body as Record<string, unknown>).accountId ??\n (body as Record<string, unknown>).sessionId ??\n \"\",\n )\n : \"\";\n\n if (!targetId) {\n return NextResponse.json({ error: \"accountId required\" }, { status: 400 });\n }\n\n const switched = await switchAccount(targetId);\n if (!switched) {\n return NextResponse.json({ error: \"Account not found\" }, { status: 404 });\n }\n\n return NextResponse.json({ ok: true });\n }\n\n async function proxy(request: NextRequest, route: string) {\n const accessToken = await getAccessToken();\n const body = [\"GET\", \"HEAD\"].includes(request.method) ? undefined : await readBody(request);\n const url = new URL(appendSearchParams(createUrl(config.issuer, mapLocalPathToApiPath(route)), request));\n applyClientCredentials(url, config);\n const requestHeaders = new Headers();\n\n if (accessToken) requestHeaders.set(\"authorization\", `Bearer ${accessToken}`);\n if (body !== undefined) requestHeaders.set(\"content-type\", \"application/json\");\n\n const response = await fetch(url, {\n method: request.method,\n headers: requestHeaders,\n body: body === undefined ? undefined : typeof body === \"string\" ? body : JSON.stringify(body),\n cache: \"no-store\",\n });\n\n const data = isJsonResponse(response) ? ((await response.json().catch(() => null)) as TokenLikeResponse | null) : null;\n if (data) {\n const tokens = tokenFromResponse(data);\n if (tokens.accessToken || tokens.refreshToken || tokens.idToken || tokens.sessionId) {\n await saveAccountToList(tokens);\n }\n return NextResponse.json(data, { status: response.status });\n }\n\n return responseFromApi(response);\n }\n\n async function handle(request: NextRequest) {\n const route = routeFromRequest(request, config.basePath);\n\n if (request.method === \"GET\" && route === \"/sign-in\") return createAuthorizeRedirect(request, \"login\");\n if (request.method === \"GET\" && route === \"/sign-up\") return createAuthorizeRedirect(request, \"register\");\n if (request.method === \"GET\" && route === \"/add-account\") return createAuthorizeRedirect(request, \"add-account\");\n if (request.method === \"GET\" && route === \"/login/google\") return createAuthorizeRedirect(request, \"google\");\n if (request.method === \"GET\" && route === \"/callback\") return exchangeCode(request);\n if (request.method === \"GET\" && route === \"/token\") {\n const accessToken = await getAccessToken();\n if (!accessToken) return NextResponse.json({ error: \"missing_token\" }, { status: 401 });\n return NextResponse.json({ accessToken });\n }\n\n if (request.method === \"GET\" && route === \"/accounts\") return handleAccountsLocal();\n if (request.method === \"POST\" && route === \"/accounts/switch\") return handleSwitchAccountLocal(request);\n if (request.method === \"GET\" && route === \"/organizations\") return handleOrganizationsLocal();\n\n if (request.method === \"POST\" && route === \"/organizations\") {\n const accessToken = await getAccessToken();\n const body = (await readBody(request)) as Record<string, unknown> | undefined;\n if (body && accessToken && !body.applicationId) {\n const claims = decodeJwtPayload(accessToken);\n const applicationId =\n (typeof claims?.application_id === \"string\" ? claims.application_id : null) ??\n (typeof claims?.client_id === \"string\" ? claims.client_id : null) ??\n (typeof claims?.applicationId === \"string\" ? claims.applicationId : null);\n if (applicationId) body.applicationId = applicationId;\n }\n const orgUrl = new URL(createUrl(config.issuer, \"/organizations\"));\n applyClientCredentials(orgUrl, config);\n const requestHeaders = new Headers();\n if (accessToken) requestHeaders.set(\"authorization\", `Bearer ${accessToken}`);\n if (body !== undefined) requestHeaders.set(\"content-type\", \"application/json\");\n const response = await fetch(orgUrl, {\n method: \"POST\",\n headers: requestHeaders,\n body: JSON.stringify(body),\n cache: \"no-store\",\n });\n return responseFromApi(response);\n }\n\n if (request.method === \"POST\" && route === \"/sign-out\") {\n await apiRequest(\"/auth/sign-out\", { method: \"POST\" }).catch(() => null);\n await removeActiveAccount();\n return NextResponse.json({ ok: true });\n }\n\n if (request.method === \"POST\" && route === \"/sign-out-all\") {\n await apiRequest(\"/auth/sign-out-all\", { method: \"POST\" }).catch(() => null);\n await clearAllSessionCookies();\n return NextResponse.json({ ok: true });\n }\n\n if (request.method === \"POST\" && route === \"/organizations/active\") {\n const body = await readBody(request);\n const organizationId =\n body && typeof body === \"object\" && \"organizationId\" in body\n ? (body as Record<string, unknown>).organizationId\n : null;\n const response = NextResponse.json({ ok: true });\n if (typeof organizationId === \"string\") {\n const cookieOpts = {\n httpOnly: true,\n sameSite: \"lax\" as const,\n path: \"/\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7,\n };\n response.cookies.set(cn.activeOrganizationId, organizationId, cookieOpts);\n }\n return response;\n }\n\n return proxy(request, route);\n }\n\n return {\n handlers: {\n GET: handle,\n POST: handle,\n PATCH: handle,\n DELETE: handle,\n },\n GetSession: getSession,\n GetUser: getUser,\n GetOrganizations: getOrganizations,\n SaveSession: saveAccountToList,\n GetAccessToken: getAccessToken,\n GetRefreshToken: getRefreshToken,\n TryRefreshTokens: tryRefreshTokens,\n RequireUser: requireUser,\n CreateAuthApiClient: createApiClient,\n cookiePrefix: config.cookiePrefix,\n VerifyToken: (token: string) => verifyToken(token, config.issuer),\n SignInUrl: async (redirectTo?: string) => {\n const configured = env(\"GEEKAPPS_APP_URL\");\n if (!configured) throw new Error(\"Cannot determine app origin. Set GEEKAPPS_APP_URL.\");\n const origin = configured.replace(/\\/$/, \"\");\n const url = new URL(`${origin}${config.basePath}/sign-in`);\n if (redirectTo) url.searchParams.set(\"redirectTo\", redirectTo);\n return url.toString();\n },\n };\n}\n\nexport function handlers(options?: GeekappsAuthConfig) {\n return configureGeekappsAuth(options).handlers;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import { cookies, headers } from \"next/headers\";\nimport { redirect } from \"next/navigation\";\nimport { NextResponse, type NextRequest } from \"next/server\";\nimport { createRemoteJWKSet, jwtVerify, type JWTPayload } from \"jose\";\n\nexport type GeekappsAuthConfig = {\n /**\n * Auth API/issuer URL. Optional when GEEKAPPS_AUTH_ISSUER or\n * GEEKAPPS_AUTH_API_URL is defined.\n */\n issuer?: string;\n\n /**\n * OAuth client id. Optional when GEEKAPPS_AUTH_CLIENT_ID is defined.\n */\n clientId?: string;\n\n /**\n * OAuth client secret for confidential clients. Optional when\n * GEEKAPPS_AUTH_CLIENT_SECRET is defined.\n */\n clientSecret?: string;\n\n /**\n * Callback URL. Optional when GEEKAPPS_AUTH_REDIRECT_URI is defined.\n * If omitted, it is inferred from the current request origin + basePath/callback.\n */\n redirectUri?: string;\n\n scopes?: string[];\n basePath?: string;\n /**\n * @deprecated cookiePrefix is now auto-derived from clientId.\n * This field is kept for backwards compatibility but is ignored.\n */\n cookiePrefix?: string;\n cookieDomain?: string;\n secureCookies?: boolean;\n\n /**\n * Friendly alias used by apps. Same as afterSignInRedirectTo.\n */\n redirectTo?: string;\n\n afterSignInRedirectTo?: string;\n afterSignOutRedirectTo?: string;\n};\n\ntype ResolvedGeekappsAuthConfig = GeekappsAuthConfig & {\n issuer: string;\n clientId: string;\n basePath: string;\n cookiePrefix: string;\n};\n\nexport type SessionTokens = {\n accessToken: string | null;\n refreshToken: string | null;\n idToken: string | null;\n sessionId: string | null;\n};\n\nexport type StoredAccount = {\n /** Stable identifier — `sub` from id_token or fallback to sessionId. */\n id: string;\n accessToken: string;\n refreshToken: string | null;\n idToken: string | null;\n sessionId: string | null;\n user: {\n sub: string;\n name?: string | null;\n email?: string | null;\n picture?: string | null;\n phone?: string | null;\n };\n};\n\nexport type ServerAuthApiClient = {\n get: <T>(path: string) => Promise<T>;\n post: <T>(path: string, body?: unknown) => Promise<T>;\n patch: <T>(path: string, body?: unknown) => Promise<T>;\n put: <T>(path: string, body?: unknown) => Promise<T>;\n delete: <T>(path: string) => Promise<T>;\n};\n\ntype JsonObject = Record<string, unknown>;\n\ntype TokenLikeResponse = JsonObject & {\n access_token?: string;\n accessToken?: string;\n refresh_token?: string;\n refreshToken?: string;\n id_token?: string;\n idToken?: string;\n session_id?: string;\n sessionId?: string;\n tokens?: {\n access_token?: string;\n accessToken?: string;\n refresh_token?: string;\n refreshToken?: string;\n id_token?: string;\n idToken?: string;\n session_id?: string;\n sessionId?: string;\n };\n};\n\nconst MAX_ACCOUNTS = 8;\n\nfunction normalizeBaseUrl(url: string) {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeBasePath(path = \"/api/auth\") {\n if (!path.startsWith(\"/\")) return `/${path}`;\n return path.replace(/\\/$/, \"\");\n}\n\nfunction createUrl(baseUrl: string, path: string) {\n if (/^https?:\\/\\//.test(path)) return path;\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${normalizeBaseUrl(baseUrl)}${normalizedPath}`;\n}\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction resolveIssuer(input: GeekappsAuthConfig) {\n return normalizeBaseUrl(\n input.issuer ??\n env(\"GEEKAPPS_AUTH_ISSUER\") ??\n env(\"GEEKAPPS_AUTH_API_URL\") ??\n \"http://localhost:3020\",\n );\n}\n\nfunction resolveClientId(input: GeekappsAuthConfig) {\n return input.clientId ?? env(\"GEEKAPPS_AUTH_CLIENT_ID\") ?? \"\";\n}\n\nfunction resolveClientSecret(input: GeekappsAuthConfig) {\n return input.clientSecret ?? env(\"GEEKAPPS_AUTH_CLIENT_SECRET\");\n}\n\nfunction applyClientCredentials(url: URL, config: ResolvedGeekappsAuthConfig) {\n if (!config.clientId || !config.clientSecret) return;\n url.searchParams.set(\"client_id\", config.clientId);\n url.searchParams.set(\"client_secret\", config.clientSecret);\n}\n\nfunction resolveConfiguredRedirectUri(input: GeekappsAuthConfig) {\n return input.redirectUri ?? env(\"GEEKAPPS_AUTH_REDIRECT_URI\");\n}\n\n/**\n * Derives a short stable 8-char hex hash from a clientId string.\n * Uses a simple djb2-style hash — no crypto dependency needed.\n */\nfunction hashClientId(clientId: string): string {\n let h = 5381;\n for (let i = 0; i < clientId.length; i++) {\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\n h = h >>> 0; // keep unsigned 32-bit\n }\n return h.toString(16).padStart(8, \"0\");\n}\n\n/**\n * Auto-derives the cookie prefix from clientId.\n * Format: `gk_{8-char-hash}` — guaranteed unique per OAuth client.\n * Falls back to `gk` when clientId is empty (dev/test environments).\n */\nfunction deriveCookiePrefix(clientId: string): string {\n if (!clientId) return \"gk\";\n return `gk_${hashClientId(clientId)}`;\n}\n\nfunction requestOrigin(request: NextRequest) {\n const configured = env(\"GEEKAPPS_APP_URL\");\n if (configured) return configured.replace(/\\/$/, \"\");\n\n throw new Error(\n \"Cannot determine app origin. Set GEEKAPPS_APP_URL.\",\n );\n}\n\nfunction resolveRedirectUri(config: ResolvedGeekappsAuthConfig, request: NextRequest) {\n return config.redirectUri ?? `${requestOrigin(request)}${config.basePath}/callback`;\n}\n\nfunction tokenFromResponse(data: TokenLikeResponse): SessionTokens {\n return {\n accessToken: data.accessToken ?? data.access_token ?? data.tokens?.accessToken ?? data.tokens?.access_token ?? null,\n refreshToken:\n data.refreshToken ?? data.refresh_token ?? data.tokens?.refreshToken ?? data.tokens?.refresh_token ?? null,\n idToken: data.idToken ?? data.id_token ?? data.tokens?.idToken ?? data.tokens?.id_token ?? null,\n sessionId: data.sessionId ?? data.session_id ?? data.tokens?.sessionId ?? data.tokens?.session_id ?? null,\n };\n}\n\n/** Decode a JWT payload without verifying signature (safe for client-visible claims). */\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length < 2) return null;\n const payload = parts[1];\n if (!payload) return null;\n return JSON.parse(Buffer.from(payload, \"base64url\").toString(\"utf8\")) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction parseAccountFromJwt(tokens: SessionTokens): StoredAccount | null {\n if (!tokens.accessToken) return null;\n\n const jwtToParse = tokens.idToken ?? tokens.accessToken;\n const payload = decodeJwtPayload(jwtToParse);\n if (!payload) return null;\n\n const sub = typeof payload.sub === \"string\" ? payload.sub : null;\n const id = sub ?? tokens.sessionId;\n if (!id) return null;\n\n return {\n id,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n idToken: tokens.idToken ?? null,\n sessionId: tokens.sessionId,\n user: {\n sub: id,\n name: typeof payload.name === \"string\" ? payload.name : null,\n email: typeof payload.email === \"string\" ? payload.email : null,\n picture: typeof payload.picture === \"string\" ? payload.picture : null,\n phone: typeof payload.phone_number === \"string\" ? payload.phone_number : null,\n },\n };\n}\n\n/**\n * Cookie name scheme — 3 cookies per slot, each well under 4096 bytes:\n *\n * {prefix}_m{n} — metadata blob (base64url JSON): { id, sid?, n?, e?, p? }\n * Claims extracted from id_token at login. Never stores tokens.\n * {prefix}_at{n} — access token (httpOnly). ~1-2 KB.\n * {prefix}_rt{n} — refresh token (httpOnly). ~1 KB.\n * {prefix}_active — active slot index (\"1\", \"2\", …)\n * {prefix}_count — total stored slots\n * {prefix}_ao — active org id for this app\n * {prefix}_tp — non-httpOnly copy of active access token for client-side axios\n *\n * id_token is NOT stored in cookies — claims are extracted at login and cached in\n * the metadata cookie. This is the key size saving.\n */\nfunction getCookieNames(prefix: string) {\n return {\n active: `${prefix}_active`,\n count: `${prefix}_count`,\n activeOrganizationId: `${prefix}_ao`,\n tokenPub: `${prefix}_tp`,\n slotMeta: (n: number) => `${prefix}_m${n}`,\n slotAt: (n: number) => `${prefix}_at${n}`,\n slotRt: (n: number) => `${prefix}_rt${n}`,\n };\n}\n\ntype SlotMeta = {\n id: string;\n sid?: string;\n n?: string;\n e?: string;\n p?: string;\n};\n\nfunction encodeMeta(account: StoredAccount): string {\n const m: SlotMeta = { id: account.id };\n if (account.sessionId) m.sid = account.sessionId;\n if (account.user.name) m.n = account.user.name;\n if (account.user.email) m.e = account.user.email;\n if (account.user.picture) m.p = account.user.picture;\n return Buffer.from(JSON.stringify(m), \"utf8\").toString(\"base64url\");\n}\n\nfunction decodeMeta(value: string): SlotMeta | null {\n try {\n const m = JSON.parse(Buffer.from(value, \"base64url\").toString(\"utf8\")) as SlotMeta;\n return m.id ? m : null;\n } catch {\n return null;\n }\n}\n\nfunction getCookieOptions(config: ResolvedGeekappsAuthConfig) {\n return {\n httpOnly: true,\n secure: config.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n ...(config.cookieDomain ? { domain: config.cookieDomain } : {}),\n };\n}\n\nasync function readBody(request: NextRequest) {\n const text = await request.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction appendSearchParams(url: string, request: NextRequest) {\n const target = new URL(url);\n request.nextUrl.searchParams.forEach((value, key) => {\n target.searchParams.set(key, value);\n });\n return target.toString();\n}\n\nfunction routeFromRequest(request: NextRequest, basePath: string) {\n const pathname = request.nextUrl.pathname;\n if (!pathname.startsWith(basePath)) return pathname;\n const route = pathname.slice(basePath.length);\n return route || \"/\";\n}\n\nfunction isJsonResponse(response: Response) {\n return response.headers.get(\"content-type\")?.includes(\"application/json\");\n}\n\nasync function responseFromApi(response: Response) {\n if (response.status === 204) return new NextResponse(null, { status: 204 });\n const body = isJsonResponse(response) ? await response.json().catch(() => null) : await response.text();\n return NextResponse.json(body, { status: response.status });\n}\n\nconst _remoteJWKSCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\n\nfunction getRemoteJWKS(issuer: string) {\n if (!_remoteJWKSCache.has(issuer)) {\n _remoteJWKSCache.set(issuer, createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`)));\n }\n return _remoteJWKSCache.get(issuer)!;\n}\n\nexport async function verifyToken(\n token: string,\n issuer: string,\n): Promise<JWTPayload | null> {\n try {\n const { payload } = await jwtVerify(token, getRemoteJWKS(issuer), {\n algorithms: [\"RS256\"],\n issuer,\n });\n return payload;\n } catch {\n return null;\n }\n}\n\nexport function configureGeekappsAuth(input: GeekappsAuthConfig = {}) {\n const clientId = resolveClientId(input);\n const config: ResolvedGeekappsAuthConfig = {\n ...input,\n issuer: resolveIssuer(input),\n clientId,\n clientSecret: resolveClientSecret(input),\n redirectUri: resolveConfiguredRedirectUri(input),\n afterSignInRedirectTo:\n input.afterSignInRedirectTo ?? input.redirectTo ?? \"/\",\n basePath: normalizeBasePath(input.basePath),\n cookiePrefix: deriveCookiePrefix(clientId),\n };\n\n const cn = getCookieNames(config.cookiePrefix);\n\n // ── Slot helpers ──────────────────────────────────────────────────────────\n\n async function getCount(): Promise<number> {\n const cookieStore = await cookies();\n const raw = cookieStore.get(cn.count)?.value;\n const n = raw ? Number.parseInt(raw, 10) : 0;\n return Number.isNaN(n) ? 0 : n;\n }\n\n async function getActiveIndex(): Promise<number> {\n const cookieStore = await cookies();\n const raw = cookieStore.get(cn.active)?.value;\n if (!raw) return 0;\n const n = Number.parseInt(raw, 10);\n return Number.isNaN(n) ? 0 : n;\n }\n\n function readSlot(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n n: number,\n ): StoredAccount | null {\n const at = cookieStore.get(cn.slotAt(n))?.value;\n if (!at) return null;\n const meta = decodeMeta(cookieStore.get(cn.slotMeta(n))?.value ?? \"\");\n if (!meta) return null;\n return {\n id: meta.id,\n accessToken: at,\n refreshToken: cookieStore.get(cn.slotRt(n))?.value ?? null,\n idToken: null, // not stored in cookies; claims are in meta\n sessionId: meta.sid ?? null,\n user: {\n sub: meta.id,\n name: meta.n ?? null,\n email: meta.e ?? null,\n picture: meta.p ?? null,\n },\n };\n }\n\n function writeSlot(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n n: number,\n account: StoredAccount,\n ) {\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n cookieStore.set(cn.slotMeta(n), encodeMeta(account), opts);\n cookieStore.set(cn.slotAt(n), account.accessToken, opts);\n if (account.refreshToken) cookieStore.set(cn.slotRt(n), account.refreshToken, opts);\n }\n\n function clearSlot(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n n: number,\n ) {\n const clear = { ...getCookieOptions(config), maxAge: 0 };\n cookieStore.set(cn.slotMeta(n), \"\", clear);\n cookieStore.set(cn.slotAt(n), \"\", clear);\n cookieStore.set(cn.slotRt(n), \"\", clear);\n }\n\n // ── Public account helpers ─────────────────────────────────────────────────\n\n async function getAccountsList(): Promise<StoredAccount[]> {\n const [cookieStore, count] = await Promise.all([cookies(), getCount()]);\n const accounts: StoredAccount[] = [];\n for (let i = 1; i <= count; i++) {\n const slot = readSlot(cookieStore, i);\n if (slot) accounts.push(slot);\n }\n return accounts;\n }\n\n async function getActiveAccount(): Promise<StoredAccount | null> {\n const [cookieStore, activeIdx, count] = await Promise.all([cookies(), getActiveIndex(), getCount()]);\n if (count === 0) return null;\n if (activeIdx >= 1 && activeIdx <= count) {\n const slot = readSlot(cookieStore, activeIdx);\n if (slot) return slot;\n }\n // Fall back to slot 1\n return readSlot(cookieStore, 1);\n }\n\n async function getAccessToken() {\n // Prefer the token injected by the middleware via request header (same-request refresh)\n try {\n const hdrs = await headers();\n const injected = hdrs.get(\"x-gk-access-token\");\n if (injected) return injected;\n } catch {}\n const active = await getActiveAccount();\n return active?.accessToken ?? null;\n }\n\n async function getRefreshToken() {\n const active = await getActiveAccount();\n return active?.refreshToken ?? null;\n }\n\n async function getSession(): Promise<SessionTokens | null> {\n const active = await getActiveAccount();\n if (!active) return null;\n return {\n accessToken: active.accessToken,\n refreshToken: active.refreshToken,\n idToken: active.idToken,\n sessionId: active.sessionId,\n };\n }\n\n async function getUser(): Promise<StoredAccount[\"user\"] | null> {\n const active = await getActiveAccount();\n return active?.user ?? null;\n }\n\n async function getOrganizations(): Promise<{ organizations: unknown[]; currentOrgId: string | null }> {\n const cookieStore = await cookies();\n const currentOrgId = cookieStore.get(cn.activeOrganizationId)?.value ?? null;\n try {\n const data = await apiRequest<unknown[] | { organizations: unknown[] }>(\"/organizations\");\n const organizations = Array.isArray(data) ? data : (data as { organizations: unknown[] }).organizations;\n return { organizations, currentOrgId };\n } catch {\n return { organizations: [], currentOrgId };\n }\n }\n\n function clearPublicTokenCookie(\n cookieStore: Awaited<ReturnType<typeof cookies>>,\n ) {\n // Clear legacy _tp cookie if present\n if (cookieStore.get(cn.tokenPub)?.value) {\n cookieStore.set(cn.tokenPub, \"\", { httpOnly: false, maxAge: 0, path: \"/\" });\n }\n }\n\n async function saveAccountToList(tokens: SessionTokens) {\n const account = parseAccountFromJwt(tokens);\n if (!account) return;\n\n const cookieStore = await cookies();\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n const count = await getCount();\n\n // Find existing slot for this account id\n let targetSlot = 0;\n for (let i = 1; i <= count; i++) {\n const existing = readSlot(cookieStore, i);\n if (existing?.id === account.id) {\n targetSlot = i;\n break;\n }\n }\n\n if (targetSlot === 0) {\n if (count >= MAX_ACCOUNTS) return;\n targetSlot = count + 1;\n cookieStore.set(cn.count, String(targetSlot), opts);\n }\n\n writeSlot(cookieStore, targetSlot, account);\n cookieStore.set(cn.active, String(targetSlot), opts);\n clearPublicTokenCookie(cookieStore);\n }\n\n // Alias for backwards compat\n const setSessionCookies = saveAccountToList;\n\n async function switchAccount(accountId: string): Promise<boolean> {\n const [cookieStore, count] = await Promise.all([cookies(), getCount()]);\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n\n for (let i = 1; i <= count; i++) {\n const slot = readSlot(cookieStore, i);\n if (slot && (slot.id === accountId || slot.sessionId === accountId)) {\n cookieStore.set(cn.active, String(i), opts);\n clearPublicTokenCookie(cookieStore);\n return true;\n }\n }\n return false;\n }\n\n async function removeActiveAccount() {\n const [cookieStore, activeIdx, count] = await Promise.all([cookies(), getActiveIndex(), getCount()]);\n const opts = { ...getCookieOptions(config), maxAge: 60 * 60 * 24 * 30 };\n const clear = { ...getCookieOptions(config), maxAge: 0 };\n\n if (count === 0) return;\n\n const remaining: StoredAccount[] = [];\n for (let i = 1; i <= count; i++) {\n if (i === activeIdx) continue;\n const slot = readSlot(cookieStore, i);\n if (slot) remaining.push(slot);\n }\n\n for (let i = 1; i <= count; i++) {\n clearSlot(cookieStore, i);\n }\n\n if (remaining.length === 0) {\n cookieStore.set(cn.count, \"0\", clear);\n cookieStore.set(cn.active, \"0\", clear);\n await clearPublicTokenCookie(cookieStore);\n return;\n }\n\n // Re-compact remaining accounts into slots 1..n\n for (let i = 0; i < remaining.length; i++) {\n await writeSlot(cookieStore, i + 1, remaining[i]!);\n }\n cookieStore.set(cn.count, String(remaining.length), opts);\n cookieStore.set(cn.active, \"1\", opts);\n clearPublicTokenCookie(cookieStore);\n }\n\n async function clearAllSessionCookies() {\n const [cookieStore, count] = await Promise.all([cookies(), getCount()]);\n const clear = { ...getCookieOptions(config), maxAge: 0 };\n for (let i = 1; i <= count; i++) {\n clearSlot(cookieStore, i);\n }\n cookieStore.set(cn.count, \"0\", clear);\n cookieStore.set(cn.active, \"0\", clear);\n clearPublicTokenCookie(cookieStore);\n }\n\n async function tryRefreshTokens(): Promise<string | null> {\n const refreshToken = await getRefreshToken();\n if (!refreshToken || !config.clientId) return null;\n\n const basicAuth = Buffer.from(`${config.clientId}:${config.clientSecret ?? \"\"}`).toString(\"base64\");\n\n const response = await fetch(createUrl(config.issuer, \"/auth/token\"), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return null;\n\n const data = (await response.json().catch(() => null)) as TokenLikeResponse | null;\n if (!data) return null;\n\n const tokens = tokenFromResponse(data);\n if (!tokens.accessToken) return null;\n\n await saveAccountToList(tokens);\n return tokens.accessToken;\n }\n\n async function apiRequest<T>(path: string, init: RequestInit = {}): Promise<T> {\n const accessToken = await getAccessToken();\n const requestHeaders = new Headers(init.headers);\n\n if (accessToken) requestHeaders.set(\"authorization\", `Bearer ${accessToken}`);\n if (init.body !== undefined && !requestHeaders.has(\"content-type\")) {\n requestHeaders.set(\"content-type\", \"application/json\");\n }\n\n const url = new URL(createUrl(config.issuer, path));\n applyClientCredentials(url, config);\n\n const response = await fetch(url, {\n ...init,\n headers: requestHeaders,\n cache: \"no-store\",\n });\n\n if (response.status === 401) {\n const newAccessToken = await tryRefreshTokens();\n if (newAccessToken) {\n const retryHeaders = new Headers(init.headers);\n retryHeaders.set(\"authorization\", `Bearer ${newAccessToken}`);\n if (init.body !== undefined && !retryHeaders.has(\"content-type\")) {\n retryHeaders.set(\"content-type\", \"application/json\");\n }\n const retryUrl = new URL(createUrl(config.issuer, path));\n applyClientCredentials(retryUrl, config);\n const retryResponse = await fetch(retryUrl, {\n ...init,\n headers: retryHeaders,\n cache: \"no-store\",\n });\n if (!retryResponse.ok) {\n const error = await retryResponse.json().catch(() => null);\n throw new Error(error?.error_description ?? error?.error ?? error?.message ?? `Auth API error ${retryResponse.status}`);\n }\n if (retryResponse.status === 204) return null as T;\n return (await retryResponse.json()) as T;\n }\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => null);\n throw new Error(error?.error_description ?? error?.error ?? error?.message ?? `Auth API error ${response.status}`);\n }\n\n if (response.status === 204) return null as T;\n return (await response.json()) as T;\n }\n\n function createApiClient(): ServerAuthApiClient {\n return {\n get: (path) => apiRequest(path),\n post: (path, body) => apiRequest(path, { method: \"POST\", body: body === undefined ? undefined : JSON.stringify(body) }),\n patch: (path, body) => apiRequest(path, { method: \"PATCH\", body: body === undefined ? undefined : JSON.stringify(body) }),\n put: (path, body) => apiRequest(path, { method: \"PUT\", body: body === undefined ? undefined : JSON.stringify(body) }),\n delete: (path) => apiRequest(path, { method: \"DELETE\" }),\n };\n }\n\n async function requireUser(options: { redirectTo?: string } = {}) {\n const accessToken = await getAccessToken();\n if (!accessToken) {\n redirect(options.redirectTo ?? \"/\");\n }\n return accessToken;\n }\n\n async function createAuthorizeRedirect(request: NextRequest, mode: \"login\" | \"register\" | \"add-account\" | \"google\") {\n const redirectTo = request.nextUrl.searchParams.get(\"redirectTo\") ?? config.afterSignInRedirectTo ?? \"/\";\n const flowId = request.nextUrl.searchParams.get(\"flow_id\");\n const url = new URL(createUrl(config.issuer, mode === \"google\" ? \"/auth/google\" : \"/authorize\"));\n\n if (!config.clientId) {\n return NextResponse.json(\n { error: \"missing_client_id\", message: \"Missing GEEKAPPS_AUTH_CLIENT_ID or clientId.\" },\n { status: 500 },\n );\n }\n\n url.searchParams.set(\"client_id\", config.clientId);\n url.searchParams.set(\"redirect_uri\", resolveRedirectUri(config, request));\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"scope\", (config.scopes ?? [\"openid\", \"profile\", \"email\"]).join(\" \"));\n url.searchParams.set(\"state\", Buffer.from(JSON.stringify({ redirectTo, mode })).toString(\"base64url\"));\n if (mode === \"register\") url.searchParams.set(\"screen_hint\", \"signup\");\n if (mode === \"add-account\") url.searchParams.set(\"prompt\", \"login\");\n if (flowId) url.searchParams.set(\"flow_id\", flowId);\n\n if (mode === \"login\") {\n url.searchParams.set(\"prompt\", \"login\");\n }\n\n return NextResponse.redirect(url);\n }\n\n async function exchangeCode(request: NextRequest) {\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!code) return NextResponse.redirect(new URL(\"/error?error=missing_code\", requestOrigin(request)));\n\n if (!config.clientId) {\n return NextResponse.json(\n { error: \"missing_client_id\", message: \"Missing GEEKAPPS_AUTH_CLIENT_ID or clientId.\" },\n { status: 500 },\n );\n }\n\n const basicAuth = Buffer.from(\n `${config.clientId}:${config.clientSecret ?? \"\"}`,\n ).toString(\"base64\");\n\n const response = await fetch(createUrl(config.issuer, \"/auth/token\"), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n redirect_uri: resolveRedirectUri(config, request),\n }),\n cache: \"no-store\",\n });\n\n const data = (await response.json().catch(() => ({}))) as TokenLikeResponse;\n if (!response.ok) {\n return NextResponse.json(data, { status: response.status });\n }\n\n await saveAccountToList(tokenFromResponse(data));\n\n let redirectTo = config.afterSignInRedirectTo ?? \"/\";\n if (state) {\n try {\n const parsed = JSON.parse(Buffer.from(state, \"base64url\").toString(\"utf8\")) as { redirectTo?: string };\n redirectTo = parsed.redirectTo ?? redirectTo;\n } catch {\n // ignore malformed state\n }\n }\n\n return NextResponse.redirect(new URL(redirectTo, requestOrigin(request)));\n }\n\n function mapLocalPathToApiPath(route: string) {\n if (route === \"/me\") return \"/auth/me\";\n if (route === \"/accounts/switch\") return \"/auth/accounts/switch\";\n if (route === \"/organizations/active\") return \"/auth/organizations/active\";\n if (route === \"/permissions/check\") return \"/auth/permissions/check\";\n if (route === \"/login/password\") return \"/auth/login/password\";\n if (route === \"/register/password\") return \"/auth/register/password\";\n if (route === \"/passwordless/link\") return \"/auth/passwordless/link\";\n return route;\n }\n\n async function handleAccountsLocal(): Promise<NextResponse> {\n const [accounts, activeIdx] = await Promise.all([getAccountsList(), getActiveIndex()]);\n\n return NextResponse.json({\n accounts: accounts.map((a, i) => ({\n id: a.id,\n sessionId: a.sessionId ?? a.id,\n isActive: i + 1 === activeIdx,\n user: {\n id: a.user.sub,\n name: a.user.name ?? null,\n email: a.user.email ?? null,\n imageUrl: a.user.picture ?? null,\n phone: a.user.phone ?? null,\n },\n })),\n });\n }\n\n async function handleOrganizationsLocal(): Promise<NextResponse> {\n const cookieStore = await cookies();\n const activeOrgId = cookieStore.get(cn.activeOrganizationId)?.value ?? null;\n try {\n const data = await apiRequest<unknown[]|{ organizations: unknown[] }>(\"/organizations\");\n const organizations = Array.isArray(data) ? data : (data as { organizations: unknown[] }).organizations;\n return NextResponse.json({ organizations, currentOrgId: activeOrgId });\n } catch {\n return NextResponse.json({ organizations: [], currentOrgId: activeOrgId });\n }\n }\n\n async function handleSwitchAccountLocal(request: NextRequest): Promise<NextResponse> {\n const body = await readBody(request);\n const targetId =\n body && typeof body === \"object\"\n ? String(\n (body as Record<string, unknown>).accountId ??\n (body as Record<string, unknown>).sessionId ??\n \"\",\n )\n : \"\";\n\n if (!targetId) {\n return NextResponse.json({ error: \"accountId required\" }, { status: 400 });\n }\n\n const switched = await switchAccount(targetId);\n if (!switched) {\n return NextResponse.json({ error: \"Account not found\" }, { status: 404 });\n }\n\n return NextResponse.json({ ok: true });\n }\n\n async function proxy(request: NextRequest, route: string) {\n const accessToken = await getAccessToken();\n const body = [\"GET\", \"HEAD\"].includes(request.method) ? undefined : await readBody(request);\n const url = new URL(appendSearchParams(createUrl(config.issuer, mapLocalPathToApiPath(route)), request));\n applyClientCredentials(url, config);\n const requestHeaders = new Headers();\n\n if (accessToken) requestHeaders.set(\"authorization\", `Bearer ${accessToken}`);\n if (body !== undefined) requestHeaders.set(\"content-type\", \"application/json\");\n\n const response = await fetch(url, {\n method: request.method,\n headers: requestHeaders,\n body: body === undefined ? undefined : typeof body === \"string\" ? body : JSON.stringify(body),\n cache: \"no-store\",\n });\n\n const data = isJsonResponse(response) ? ((await response.json().catch(() => null)) as TokenLikeResponse | null) : null;\n if (data) {\n const tokens = tokenFromResponse(data);\n if (tokens.accessToken || tokens.refreshToken || tokens.idToken || tokens.sessionId) {\n await saveAccountToList(tokens);\n }\n return NextResponse.json(data, { status: response.status });\n }\n\n return responseFromApi(response);\n }\n\n async function handle(request: NextRequest) {\n const route = routeFromRequest(request, config.basePath);\n\n if (request.method === \"GET\" && route === \"/sign-in\") return createAuthorizeRedirect(request, \"login\");\n if (request.method === \"GET\" && route === \"/sign-up\") return createAuthorizeRedirect(request, \"register\");\n if (request.method === \"GET\" && route === \"/add-account\") return createAuthorizeRedirect(request, \"add-account\");\n if (request.method === \"GET\" && route === \"/login/google\") return createAuthorizeRedirect(request, \"google\");\n if (request.method === \"GET\" && route === \"/callback\") return exchangeCode(request);\n if (request.method === \"GET\" && route === \"/token\") {\n const accessToken = await getAccessToken();\n if (!accessToken) return NextResponse.json({ error: \"missing_token\" }, { status: 401 });\n return NextResponse.json({ accessToken });\n }\n\n if (request.method === \"GET\" && route === \"/accounts\") return handleAccountsLocal();\n if (request.method === \"POST\" && route === \"/accounts/switch\") return handleSwitchAccountLocal(request);\n if (request.method === \"GET\" && route === \"/organizations\") return handleOrganizationsLocal();\n\n if (request.method === \"POST\" && route === \"/organizations\") {\n const accessToken = await getAccessToken();\n const body = (await readBody(request)) as Record<string, unknown> | undefined;\n if (body && accessToken && !body.applicationId) {\n const claims = decodeJwtPayload(accessToken);\n const applicationId =\n (typeof claims?.application_id === \"string\" ? claims.application_id : null) ??\n (typeof claims?.client_id === \"string\" ? claims.client_id : null) ??\n (typeof claims?.applicationId === \"string\" ? claims.applicationId : null);\n if (applicationId) body.applicationId = applicationId;\n }\n const orgUrl = new URL(createUrl(config.issuer, \"/organizations\"));\n applyClientCredentials(orgUrl, config);\n const requestHeaders = new Headers();\n if (accessToken) requestHeaders.set(\"authorization\", `Bearer ${accessToken}`);\n if (body !== undefined) requestHeaders.set(\"content-type\", \"application/json\");\n const response = await fetch(orgUrl, {\n method: \"POST\",\n headers: requestHeaders,\n body: JSON.stringify(body),\n cache: \"no-store\",\n });\n return responseFromApi(response);\n }\n\n if (request.method === \"POST\" && route === \"/sign-out\") {\n await apiRequest(\"/auth/sign-out\", { method: \"POST\" }).catch(() => null);\n await removeActiveAccount();\n return NextResponse.json({ ok: true });\n }\n\n if (request.method === \"POST\" && route === \"/sign-out-all\") {\n await apiRequest(\"/auth/sign-out-all\", { method: \"POST\" }).catch(() => null);\n await clearAllSessionCookies();\n return NextResponse.json({ ok: true });\n }\n\n if (request.method === \"POST\" && route === \"/organizations/active\") {\n const body = await readBody(request);\n const organizationId =\n body && typeof body === \"object\" && \"organizationId\" in body\n ? (body as Record<string, unknown>).organizationId\n : null;\n const response = NextResponse.json({ ok: true });\n if (typeof organizationId === \"string\") {\n const cookieOpts = {\n httpOnly: true,\n sameSite: \"lax\" as const,\n path: \"/\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7,\n };\n response.cookies.set(cn.activeOrganizationId, organizationId, cookieOpts);\n }\n return response;\n }\n\n return proxy(request, route);\n }\n\n return {\n handlers: {\n GET: handle,\n POST: handle,\n PATCH: handle,\n DELETE: handle,\n },\n GetSession: getSession,\n GetUser: getUser,\n GetOrganizations: getOrganizations,\n SaveSession: saveAccountToList,\n GetAccessToken: getAccessToken,\n GetRefreshToken: getRefreshToken,\n TryRefreshTokens: tryRefreshTokens,\n RequireUser: requireUser,\n CreateAuthApiClient: createApiClient,\n cookiePrefix: config.cookiePrefix,\n VerifyToken: (token: string) => verifyToken(token, config.issuer),\n SignInUrl: async (redirectTo?: string) => {\n const configured = env(\"GEEKAPPS_APP_URL\");\n if (!configured) throw new Error(\"Cannot determine app origin. Set GEEKAPPS_APP_URL.\");\n const origin = configured.replace(/\\/$/, \"\");\n const url = new URL(`${origin}${config.basePath}/sign-in`);\n if (redirectTo) url.searchParams.set(\"redirectTo\", redirectTo);\n return url.toString();\n },\n };\n}\n\nexport function handlers(options?: GeekappsAuthConfig) {\n return configureGeekappsAuth(options).handlers;\n}\n"],"mappings":"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","names":[]}
|