@cortejojicoy/admin-kit 0.1.8

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.
@@ -0,0 +1,115 @@
1
+ // src/auth/server/verifyJWT.ts
2
+ var enc = new TextEncoder();
3
+ function toAB(view) {
4
+ const buf = new ArrayBuffer(view.byteLength);
5
+ new Uint8Array(buf).set(view);
6
+ return buf;
7
+ }
8
+ function base64UrlDecode(input) {
9
+ const pad = input.length % 4 === 0 ? "" : "=".repeat(4 - input.length % 4);
10
+ const b64 = (input + pad).replace(/-/g, "+").replace(/_/g, "/");
11
+ const bin = typeof atob === "function" ? atob(b64) : Buffer.from(b64, "base64").toString("binary");
12
+ const out = new Uint8Array(new ArrayBuffer(bin.length));
13
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
14
+ return out;
15
+ }
16
+ function decodeJSON(seg) {
17
+ const bytes = base64UrlDecode(seg);
18
+ const text = new TextDecoder().decode(bytes);
19
+ return JSON.parse(text);
20
+ }
21
+ var ALGS = {
22
+ HS256: { name: "HMAC", hash: "SHA-256" },
23
+ HS384: { name: "HMAC", hash: "SHA-384" },
24
+ HS512: { name: "HMAC", hash: "SHA-512" }
25
+ };
26
+ async function verifyJWT(token, secret) {
27
+ const parts = token.split(".");
28
+ if (parts.length !== 3) return { valid: false, payload: null, reason: "malformed" };
29
+ const [headerSeg, payloadSeg, sigSeg] = parts;
30
+ let header;
31
+ try {
32
+ header = decodeJSON(headerSeg);
33
+ } catch {
34
+ return { valid: false, payload: null, reason: "bad-header" };
35
+ }
36
+ const algSpec = header.alg ? ALGS[header.alg] : void 0;
37
+ if (!algSpec) return { valid: false, payload: null, reason: `unsupported-alg:${header.alg}` };
38
+ const key = await crypto.subtle.importKey(
39
+ "raw",
40
+ toAB(enc.encode(secret)),
41
+ { name: "HMAC", hash: algSpec.hash },
42
+ false,
43
+ ["verify"]
44
+ );
45
+ const data = toAB(enc.encode(`${headerSeg}.${payloadSeg}`));
46
+ const sig = toAB(base64UrlDecode(sigSeg));
47
+ const ok = await crypto.subtle.verify("HMAC", key, sig, data);
48
+ if (!ok) return { valid: false, payload: null, reason: "bad-signature" };
49
+ let payload;
50
+ try {
51
+ payload = decodeJSON(payloadSeg);
52
+ } catch {
53
+ return { valid: false, payload: null, reason: "bad-payload" };
54
+ }
55
+ const now = Math.floor(Date.now() / 1e3);
56
+ if (payload.exp != null && now >= payload.exp) return { valid: false, payload, reason: "expired" };
57
+ if (payload.nbf != null && now < payload.nbf) return { valid: false, payload, reason: "not-yet-valid" };
58
+ return { valid: true, payload };
59
+ }
60
+
61
+ // src/auth/server/cookies.ts
62
+ function parseCookies(header) {
63
+ if (!header) return {};
64
+ const out = {};
65
+ for (const part of header.split(";")) {
66
+ const idx = part.indexOf("=");
67
+ if (idx === -1) continue;
68
+ const k = part.slice(0, idx).trim();
69
+ const v = part.slice(idx + 1).trim();
70
+ if (k) out[k] = decodeURIComponent(v);
71
+ }
72
+ return out;
73
+ }
74
+
75
+ // src/middleware.ts
76
+ var DEFAULT_COOKIE = "admin_kit_token";
77
+ function createAdminMiddleware(config, opts = {}) {
78
+ const publicRoutes = [
79
+ ...config.auth.publicRoutes ?? ["/login", "/api/auth"],
80
+ ...opts.publicRoutes ?? []
81
+ ];
82
+ const loginPath = config.auth.loginPage?.path ?? "/login";
83
+ const cookieName = config.auth.jwt?.cookieName ?? DEFAULT_COOKIE;
84
+ const secret = config.auth.jwt?.secret;
85
+ const verify = opts.verify ?? (secret ? async (token) => {
86
+ const r = await verifyJWT(token, secret);
87
+ return { valid: r.valid };
88
+ } : void 0);
89
+ return async function adminMiddleware(req) {
90
+ const url = new URL(req.url);
91
+ const pathname = url.pathname;
92
+ if (publicRoutes.some((p) => pathname === p || pathname.startsWith(p + "/"))) {
93
+ return passthrough();
94
+ }
95
+ const token = parseCookies(req.headers.get("cookie"))[cookieName];
96
+ if (!token) return redirectToLogin(url, pathname, loginPath);
97
+ if (verify) {
98
+ const { valid } = await verify(token);
99
+ if (!valid) return redirectToLogin(url, pathname, loginPath);
100
+ }
101
+ return passthrough();
102
+ };
103
+ }
104
+ function passthrough() {
105
+ return new Response(null, { status: 200 });
106
+ }
107
+ function redirectToLogin(url, pathname, loginPath) {
108
+ const target = new URL(loginPath, url.origin);
109
+ target.searchParams.set("next", pathname);
110
+ return Response.redirect(target.toString(), 307);
111
+ }
112
+
113
+ export { createAdminMiddleware };
114
+ //# sourceMappingURL=middleware.js.map
115
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/server/verifyJWT.ts","../src/auth/server/cookies.ts","../src/middleware.ts"],"names":[],"mappings":";AAOA,IAAM,GAAA,GAAM,IAAI,WAAA,EAAY;AAQ5B,SAAS,KAAK,IAAA,EAA+B;AAC3C,EAAA,MAAM,GAAA,GAAM,IAAI,WAAA,CAAY,IAAA,CAAK,UAAU,CAAA;AAC3C,EAAA,IAAI,UAAA,CAAW,GAAG,CAAA,CAAE,GAAA,CAAI,IAAI,CAAA;AAC5B,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,gBAAgB,KAAA,EAAwC;AAC/D,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,MAAA,GAAS,CAAA,KAAM,CAAA,GAAI,EAAA,GAAK,GAAA,CAAI,MAAA,CAAO,CAAA,GAAK,KAAA,CAAM,MAAA,GAAS,CAAE,CAAA;AAC3E,EAAA,MAAM,GAAA,GAAA,CAAO,QAAQ,GAAA,EAAK,OAAA,CAAQ,MAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA;AAC9D,EAAA,MAAM,GAAA,GAAM,OAAO,IAAA,KAAS,UAAA,GAAa,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,QAAQ,CAAA,CAAE,SAAS,QAAQ,CAAA;AACjG,EAAA,MAAM,MAAM,IAAI,UAAA,CAAW,IAAI,WAAA,CAAY,GAAA,CAAI,MAAM,CAAC,CAAA;AACtD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,CAAA,EAAA,EAAK,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA,CAAI,UAAA,CAAW,CAAC,CAAA;AAC9D,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,WAAc,GAAA,EAAgB;AACrC,EAAA,MAAM,KAAA,GAAQ,gBAAgB,GAAG,CAAA;AACjC,EAAA,MAAM,IAAA,GAAO,IAAI,WAAA,EAAY,CAAE,OAAO,KAAK,CAAA;AAC3C,EAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AACxB;AAEA,IAAM,IAAA,GAAuD;AAAA,EAC3D,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,SAAA,EAAU;AAAA,EACvC,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,SAAA,EAAU;AAAA,EACvC,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,SAAA;AAC/B,CAAA;AAgBA,eAAsB,SAAA,CAAU,OAAe,MAAA,EAAuC;AACpF,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAE,OAAO,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,MAAA,EAAQ,WAAA,EAAY;AAClF,EAAA,MAAM,CAAC,SAAA,EAAW,UAAA,EAAY,MAAM,CAAA,GAAI,KAAA;AACxC,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,WAA2C,SAAS,CAAA;AAAA,EAC/D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,QAAQ,YAAA,EAAa;AAAA,EAC7D;AACA,EAAA,MAAM,UAAU,MAAA,CAAO,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA;AAChD,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,MAAA,EAAQ,CAAA,gBAAA,EAAmB,MAAA,CAAO,GAAG,CAAA,CAAA,EAAG;AAE5F,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,IAC9B,KAAA;AAAA,IACA,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,MAAM,CAAC,CAAA;AAAA,IACvB,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,QAAQ,IAAA,EAAK;AAAA,IACnC,KAAA;AAAA,IACA,CAAC,QAAQ;AAAA,GACX;AACA,EAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,MAAA,CAAO,GAAG,SAAS,CAAA,CAAA,EAAI,UAAU,CAAA,CAAE,CAAC,CAAA;AAC1D,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAC,CAAA;AACxC,EAAA,MAAM,EAAA,GAAK,MAAM,MAAA,CAAO,MAAA,CAAO,OAAO,MAAA,EAAQ,GAAA,EAAK,KAAK,IAAI,CAAA;AAC5D,EAAA,IAAI,CAAC,IAAI,OAAO,EAAE,OAAO,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,MAAA,EAAQ,eAAA,EAAgB;AAEvE,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,WAAuB,UAAU,CAAA;AAAA,EAC7C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,QAAQ,aAAA,EAAc;AAAA,EAC9D;AAEA,EAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,KAAQ,GAAI,CAAA;AACxC,EAAA,IAAI,OAAA,CAAQ,GAAA,IAAO,IAAA,IAAQ,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAK,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,MAAA,EAAQ,SAAA,EAAU;AACjG,EAAA,IAAI,OAAA,CAAQ,GAAA,IAAO,IAAA,IAAQ,GAAA,GAAM,OAAA,CAAQ,GAAA,EAAK,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,MAAA,EAAQ,eAAA,EAAgB;AAEtG,EAAA,OAAO,EAAE,KAAA,EAAO,IAAA,EAAM,OAAA,EAAQ;AAChC;;;ACpEO,SAAS,aAAa,MAAA,EAA2D;AACtF,EAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAC;AACrB,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,EAAG;AACpC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC5B,IAAA,IAAI,QAAQ,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,EAAE,IAAA,EAAK;AAClC,IAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAC,EAAE,IAAA,EAAK;AACnC,IAAA,IAAI,CAAA,EAAG,GAAA,CAAI,CAAC,CAAA,GAAI,mBAAmB,CAAC,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,GAAA;AACT;;;ACpBA,IAAM,cAAA,GAAiB,iBAAA;AAWhB,SAAS,qBAAA,CACd,MAAA,EACA,IAAA,GAA+B,EAAC,EACb;AACnB,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,GAAI,MAAA,CAAO,IAAA,CAAK,YAAA,IAAgB,CAAC,UAAU,WAAW,CAAA;AAAA,IACtD,GAAI,IAAA,CAAK,YAAA,IAAgB;AAAC,GAC5B;AACA,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,IAAA,IAAQ,QAAA;AACjD,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,UAAA,IAAc,cAAA;AAClD,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,MAAA;AAChC,EAAA,MAAM,MAAA,GACJ,IAAA,CAAK,MAAA,KACJ,MAAA,GACG,OAAO,KAAA,KAAkB;AACvB,IAAA,MAAM,CAAA,GAAI,MAAM,SAAA,CAAU,KAAA,EAAO,MAAM,CAAA;AACvC,IAAA,OAAO,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM;AAAA,EAC1B,CAAA,GACA,MAAA,CAAA;AAEN,EAAA,OAAO,eAAe,gBAAgB,GAAA,EAAiC;AACrE,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAC3B,IAAA,MAAM,WAAW,GAAA,CAAI,QAAA;AAErB,IAAA,IAAI,YAAA,CAAa,IAAA,CAAK,CAAC,CAAA,KAAM,QAAA,KAAa,CAAA,IAAK,QAAA,CAAS,UAAA,CAAW,CAAA,GAAI,GAAG,CAAC,CAAA,EAAG;AAC5E,MAAA,OAAO,WAAA,EAAY;AAAA,IACrB;AAEA,IAAA,MAAM,KAAA,GAAQ,aAAa,GAAA,CAAI,OAAA,CAAQ,IAAI,QAAQ,CAAC,EAAE,UAAU,CAAA;AAChE,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,eAAA,CAAgB,GAAA,EAAK,UAAU,SAAS,CAAA;AAE3D,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,OAAO,KAAK,CAAA;AACpC,MAAA,IAAI,CAAC,KAAA,EAAO,OAAO,eAAA,CAAgB,GAAA,EAAK,UAAU,SAAS,CAAA;AAAA,IAC7D;AAGA,IAAA,OAAO,WAAA,EAAY;AAAA,EACrB,CAAA;AACF;AAEA,SAAS,WAAA,GAAwB;AAK/B,EAAA,OAAO,IAAI,QAAA,CAAS,IAAA,EAAM,EAAE,MAAA,EAAQ,KAAK,CAAA;AAC3C;AAEA,SAAS,eAAA,CAAgB,GAAA,EAAU,QAAA,EAAkB,SAAA,EAA6B;AAChF,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,SAAA,EAAW,IAAI,MAAM,CAAA;AAC5C,EAAA,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,QAAQ,CAAA;AACxC,EAAA,OAAO,QAAA,CAAS,QAAA,CAAS,MAAA,CAAO,QAAA,IAAY,GAAG,CAAA;AACjD","file":"middleware.js","sourcesContent":["/**\n * Edge-safe JWT verification using the Web Crypto API.\n * Supports HS256 / HS384 / HS512. For RS-family or ES-family algorithms,\n * plug in `jose` via the `verify` option on createAdminMiddleware\n * (custom verifier).\n */\n\nconst enc = new TextEncoder()\n\n/**\n * Web Crypto's `BufferSource` requires `Uint8Array<ArrayBuffer>`. Newer TS\n * lib types widen `TextEncoder.encode()` / typed arrays to `ArrayBufferLike`,\n * which leaks `SharedArrayBuffer` into the type. Copy into a fresh ArrayBuffer\n * so the call sites typecheck cleanly without `as` casts.\n */\nfunction toAB(view: Uint8Array): ArrayBuffer {\n const buf = new ArrayBuffer(view.byteLength)\n new Uint8Array(buf).set(view)\n return buf\n}\n\nfunction base64UrlDecode(input: string): Uint8Array<ArrayBuffer> {\n const pad = input.length % 4 === 0 ? '' : '='.repeat(4 - (input.length % 4))\n const b64 = (input + pad).replace(/-/g, '+').replace(/_/g, '/')\n const bin = typeof atob === 'function' ? atob(b64) : Buffer.from(b64, 'base64').toString('binary')\n const out = new Uint8Array(new ArrayBuffer(bin.length))\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nfunction decodeJSON<T>(seg: string): T {\n const bytes = base64UrlDecode(seg)\n const text = new TextDecoder().decode(bytes)\n return JSON.parse(text) as T\n}\n\nconst ALGS: Record<string, { name: 'HMAC'; hash: string }> = {\n HS256: { name: 'HMAC', hash: 'SHA-256' },\n HS384: { name: 'HMAC', hash: 'SHA-384' },\n HS512: { name: 'HMAC', hash: 'SHA-512' },\n}\n\nexport interface JWTPayload {\n sub?: string\n exp?: number\n iat?: number\n nbf?: number\n [key: string]: unknown\n}\n\nexport interface VerifyResult {\n valid: boolean\n payload: JWTPayload | null\n reason?: string\n}\n\nexport async function verifyJWT(token: string, secret: string): Promise<VerifyResult> {\n const parts = token.split('.')\n if (parts.length !== 3) return { valid: false, payload: null, reason: 'malformed' }\n const [headerSeg, payloadSeg, sigSeg] = parts\n let header: { alg?: string; typ?: string }\n try {\n header = decodeJSON<{ alg?: string; typ?: string }>(headerSeg)\n } catch {\n return { valid: false, payload: null, reason: 'bad-header' }\n }\n const algSpec = header.alg ? ALGS[header.alg] : undefined\n if (!algSpec) return { valid: false, payload: null, reason: `unsupported-alg:${header.alg}` }\n\n const key = await crypto.subtle.importKey(\n 'raw',\n toAB(enc.encode(secret)),\n { name: 'HMAC', hash: algSpec.hash },\n false,\n ['verify'],\n )\n const data = toAB(enc.encode(`${headerSeg}.${payloadSeg}`))\n const sig = toAB(base64UrlDecode(sigSeg))\n const ok = await crypto.subtle.verify('HMAC', key, sig, data)\n if (!ok) return { valid: false, payload: null, reason: 'bad-signature' }\n\n let payload: JWTPayload\n try {\n payload = decodeJSON<JWTPayload>(payloadSeg)\n } catch {\n return { valid: false, payload: null, reason: 'bad-payload' }\n }\n\n const now = Math.floor(Date.now() / 1000)\n if (payload.exp != null && now >= payload.exp) return { valid: false, payload, reason: 'expired' }\n if (payload.nbf != null && now < payload.nbf) return { valid: false, payload, reason: 'not-yet-valid' }\n\n return { valid: true, payload }\n}\n","/**\n * Edge-safe cookie helpers used by middleware and server helpers.\n * Avoid importing anything React/DOM here.\n */\n\nexport interface CookieOptions {\n path?: string\n maxAge?: number\n domain?: string\n secure?: boolean\n httpOnly?: boolean\n sameSite?: 'lax' | 'strict' | 'none'\n}\n\nexport function serializeCookie(name: string, value: string, opts: CookieOptions = {}): string {\n const parts = [`${name}=${encodeURIComponent(value)}`]\n parts.push(`Path=${opts.path ?? '/'}`)\n if (opts.maxAge != null) parts.push(`Max-Age=${opts.maxAge}`)\n if (opts.domain) parts.push(`Domain=${opts.domain}`)\n if (opts.secure) parts.push('Secure')\n if (opts.httpOnly) parts.push('HttpOnly')\n parts.push(`SameSite=${opts.sameSite ?? 'Lax'}`)\n return parts.join('; ')\n}\n\nexport function parseCookies(header: string | null | undefined): Record<string, string> {\n if (!header) return {}\n const out: Record<string, string> = {}\n for (const part of header.split(';')) {\n const idx = part.indexOf('=')\n if (idx === -1) continue\n const k = part.slice(0, idx).trim()\n const v = part.slice(idx + 1).trim()\n if (k) out[k] = decodeURIComponent(v)\n }\n return out\n}\n\nexport function readCookieFromRequest(req: Request, name: string): string | null {\n return parseCookies(req.headers.get('cookie'))[name] ?? null\n}\n","/**\n * Edge-safe middleware factory. Mount in the consumer's `middleware.ts`:\n *\n * // middleware.ts (consumer)\n * import { createAdminMiddleware } from '@cortejojicoy/admin-kit/middleware'\n * import { adminConfig } from './admin.config'\n *\n * export default createAdminMiddleware(adminConfig)\n * export const config = { matcher: ['/((?!_next|api/auth|favicon).*)'] }\n *\n * Keep this file free of React / DOM / Node-only deps.\n */\nimport type { AdminConfig } from './config/types'\nimport { verifyJWT } from './auth/server/verifyJWT'\nimport { parseCookies } from './auth/server/cookies'\n\nconst DEFAULT_COOKIE = 'admin_kit_token'\n\nexport interface AdminMiddlewareOptions {\n /** Override token verification (e.g., RS256 with `jose`). */\n verify?: (token: string) => Promise<{ valid: boolean }>\n /** Extra public routes that bypass auth. Merged with config.auth.publicRoutes. */\n publicRoutes?: string[]\n}\n\ntype MiddlewareHandler = (req: Request) => Response | Promise<Response>\n\nexport function createAdminMiddleware(\n config: AdminConfig,\n opts: AdminMiddlewareOptions = {},\n): MiddlewareHandler {\n const publicRoutes = [\n ...(config.auth.publicRoutes ?? ['/login', '/api/auth']),\n ...(opts.publicRoutes ?? []),\n ]\n const loginPath = config.auth.loginPage?.path ?? '/login'\n const cookieName = config.auth.jwt?.cookieName ?? DEFAULT_COOKIE\n const secret = config.auth.jwt?.secret\n const verify =\n opts.verify ??\n (secret\n ? async (token: string) => {\n const r = await verifyJWT(token, secret)\n return { valid: r.valid }\n }\n : undefined)\n\n return async function adminMiddleware(req: Request): Promise<Response> {\n const url = new URL(req.url)\n const pathname = url.pathname\n\n if (publicRoutes.some((p) => pathname === p || pathname.startsWith(p + '/'))) {\n return passthrough()\n }\n\n const token = parseCookies(req.headers.get('cookie'))[cookieName]\n if (!token) return redirectToLogin(url, pathname, loginPath)\n\n if (verify) {\n const { valid } = await verify(token)\n if (!valid) return redirectToLogin(url, pathname, loginPath)\n }\n // If no verifier is configured (oauth/custom), trust the cookie's existence\n // and let server helpers / API routes do the real check.\n return passthrough()\n }\n}\n\nfunction passthrough(): Response {\n // Returning a non-redirect Response with no body and 200 acts as a passthrough\n // in Next middleware semantics when used via NextResponse. The expected pattern\n // is for consumers to wrap this with NextResponse.next() if they need the\n // typed return. We return a plain Response that next() can interpret.\n return new Response(null, { status: 200 })\n}\n\nfunction redirectToLogin(url: URL, pathname: string, loginPath: string): Response {\n const target = new URL(loginPath, url.origin)\n target.searchParams.set('next', pathname)\n return Response.redirect(target.toString(), 307)\n}\n"]}
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ // src/auth/server/verifyJWT.ts
4
+ var enc = new TextEncoder();
5
+ function toAB(view) {
6
+ const buf = new ArrayBuffer(view.byteLength);
7
+ new Uint8Array(buf).set(view);
8
+ return buf;
9
+ }
10
+ function base64UrlDecode(input) {
11
+ const pad = input.length % 4 === 0 ? "" : "=".repeat(4 - input.length % 4);
12
+ const b64 = (input + pad).replace(/-/g, "+").replace(/_/g, "/");
13
+ const bin = typeof atob === "function" ? atob(b64) : Buffer.from(b64, "base64").toString("binary");
14
+ const out = new Uint8Array(new ArrayBuffer(bin.length));
15
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
16
+ return out;
17
+ }
18
+ function decodeJSON(seg) {
19
+ const bytes = base64UrlDecode(seg);
20
+ const text = new TextDecoder().decode(bytes);
21
+ return JSON.parse(text);
22
+ }
23
+ var ALGS = {
24
+ HS256: { name: "HMAC", hash: "SHA-256" },
25
+ HS384: { name: "HMAC", hash: "SHA-384" },
26
+ HS512: { name: "HMAC", hash: "SHA-512" }
27
+ };
28
+ async function verifyJWT(token, secret) {
29
+ const parts = token.split(".");
30
+ if (parts.length !== 3) return { valid: false, payload: null, reason: "malformed" };
31
+ const [headerSeg, payloadSeg, sigSeg] = parts;
32
+ let header;
33
+ try {
34
+ header = decodeJSON(headerSeg);
35
+ } catch {
36
+ return { valid: false, payload: null, reason: "bad-header" };
37
+ }
38
+ const algSpec = header.alg ? ALGS[header.alg] : void 0;
39
+ if (!algSpec) return { valid: false, payload: null, reason: `unsupported-alg:${header.alg}` };
40
+ const key = await crypto.subtle.importKey(
41
+ "raw",
42
+ toAB(enc.encode(secret)),
43
+ { name: "HMAC", hash: algSpec.hash },
44
+ false,
45
+ ["verify"]
46
+ );
47
+ const data = toAB(enc.encode(`${headerSeg}.${payloadSeg}`));
48
+ const sig = toAB(base64UrlDecode(sigSeg));
49
+ const ok = await crypto.subtle.verify("HMAC", key, sig, data);
50
+ if (!ok) return { valid: false, payload: null, reason: "bad-signature" };
51
+ let payload;
52
+ try {
53
+ payload = decodeJSON(payloadSeg);
54
+ } catch {
55
+ return { valid: false, payload: null, reason: "bad-payload" };
56
+ }
57
+ const now = Math.floor(Date.now() / 1e3);
58
+ if (payload.exp != null && now >= payload.exp) return { valid: false, payload, reason: "expired" };
59
+ if (payload.nbf != null && now < payload.nbf) return { valid: false, payload, reason: "not-yet-valid" };
60
+ return { valid: true, payload };
61
+ }
62
+
63
+ // src/auth/server/cookies.ts
64
+ function serializeCookie(name, value, opts = {}) {
65
+ const parts = [`${name}=${encodeURIComponent(value)}`];
66
+ parts.push(`Path=${opts.path ?? "/"}`);
67
+ if (opts.maxAge != null) parts.push(`Max-Age=${opts.maxAge}`);
68
+ if (opts.domain) parts.push(`Domain=${opts.domain}`);
69
+ if (opts.secure) parts.push("Secure");
70
+ if (opts.httpOnly) parts.push("HttpOnly");
71
+ parts.push(`SameSite=${opts.sameSite ?? "Lax"}`);
72
+ return parts.join("; ");
73
+ }
74
+ function parseCookies(header) {
75
+ if (!header) return {};
76
+ const out = {};
77
+ for (const part of header.split(";")) {
78
+ const idx = part.indexOf("=");
79
+ if (idx === -1) continue;
80
+ const k = part.slice(0, idx).trim();
81
+ const v = part.slice(idx + 1).trim();
82
+ if (k) out[k] = decodeURIComponent(v);
83
+ }
84
+ return out;
85
+ }
86
+ function readCookieFromRequest(req, name) {
87
+ return parseCookies(req.headers.get("cookie"))[name] ?? null;
88
+ }
89
+
90
+ // src/auth/server/getServerSession.ts
91
+ var DEFAULT_COOKIE = "admin_kit_token";
92
+ async function getServerSession(config, req) {
93
+ if (config.auth.provider === "jwt") {
94
+ const jwt = config.auth.jwt;
95
+ if (!jwt?.secret) {
96
+ throw new Error("config.auth.jwt.secret is required for getServerSession()");
97
+ }
98
+ const cookieHeader = getCookieHeader(req);
99
+ const cookieName = jwt.cookieName ?? DEFAULT_COOKIE;
100
+ const token = parseCookies(cookieHeader)[cookieName];
101
+ if (!token) return null;
102
+ const result = await verifyJWT(token, jwt.secret);
103
+ if (!result.valid || !result.payload) return null;
104
+ const mapUser = jwt.mapUser ?? ((raw) => raw);
105
+ return {
106
+ user: mapUser(result.payload),
107
+ accessToken: token,
108
+ expiresAt: result.payload.exp
109
+ };
110
+ }
111
+ if (config.auth.provider === "custom" && config.auth.custom?.getSession) {
112
+ return config.auth.custom.getSession();
113
+ }
114
+ return null;
115
+ }
116
+ function getCookieHeader(req) {
117
+ const headers = req.headers;
118
+ if (headers instanceof Headers) return headers.get("cookie");
119
+ return headers.cookie ?? null;
120
+ }
121
+
122
+ exports.getServerSession = getServerSession;
123
+ exports.parseCookies = parseCookies;
124
+ exports.readCookieFromRequest = readCookieFromRequest;
125
+ exports.serializeCookie = serializeCookie;
126
+ exports.verifyJWT = verifyJWT;
127
+ //# sourceMappingURL=server.cjs.map
128
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/server/verifyJWT.ts","../src/auth/server/cookies.ts","../src/auth/server/getServerSession.ts"],"names":[],"mappings":"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","file":"server.cjs","sourcesContent":["/**\n * Edge-safe JWT verification using the Web Crypto API.\n * Supports HS256 / HS384 / HS512. For RS-family or ES-family algorithms,\n * plug in `jose` via the `verify` option on createAdminMiddleware\n * (custom verifier).\n */\n\nconst enc = new TextEncoder()\n\n/**\n * Web Crypto's `BufferSource` requires `Uint8Array<ArrayBuffer>`. Newer TS\n * lib types widen `TextEncoder.encode()` / typed arrays to `ArrayBufferLike`,\n * which leaks `SharedArrayBuffer` into the type. Copy into a fresh ArrayBuffer\n * so the call sites typecheck cleanly without `as` casts.\n */\nfunction toAB(view: Uint8Array): ArrayBuffer {\n const buf = new ArrayBuffer(view.byteLength)\n new Uint8Array(buf).set(view)\n return buf\n}\n\nfunction base64UrlDecode(input: string): Uint8Array<ArrayBuffer> {\n const pad = input.length % 4 === 0 ? '' : '='.repeat(4 - (input.length % 4))\n const b64 = (input + pad).replace(/-/g, '+').replace(/_/g, '/')\n const bin = typeof atob === 'function' ? atob(b64) : Buffer.from(b64, 'base64').toString('binary')\n const out = new Uint8Array(new ArrayBuffer(bin.length))\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nfunction decodeJSON<T>(seg: string): T {\n const bytes = base64UrlDecode(seg)\n const text = new TextDecoder().decode(bytes)\n return JSON.parse(text) as T\n}\n\nconst ALGS: Record<string, { name: 'HMAC'; hash: string }> = {\n HS256: { name: 'HMAC', hash: 'SHA-256' },\n HS384: { name: 'HMAC', hash: 'SHA-384' },\n HS512: { name: 'HMAC', hash: 'SHA-512' },\n}\n\nexport interface JWTPayload {\n sub?: string\n exp?: number\n iat?: number\n nbf?: number\n [key: string]: unknown\n}\n\nexport interface VerifyResult {\n valid: boolean\n payload: JWTPayload | null\n reason?: string\n}\n\nexport async function verifyJWT(token: string, secret: string): Promise<VerifyResult> {\n const parts = token.split('.')\n if (parts.length !== 3) return { valid: false, payload: null, reason: 'malformed' }\n const [headerSeg, payloadSeg, sigSeg] = parts\n let header: { alg?: string; typ?: string }\n try {\n header = decodeJSON<{ alg?: string; typ?: string }>(headerSeg)\n } catch {\n return { valid: false, payload: null, reason: 'bad-header' }\n }\n const algSpec = header.alg ? ALGS[header.alg] : undefined\n if (!algSpec) return { valid: false, payload: null, reason: `unsupported-alg:${header.alg}` }\n\n const key = await crypto.subtle.importKey(\n 'raw',\n toAB(enc.encode(secret)),\n { name: 'HMAC', hash: algSpec.hash },\n false,\n ['verify'],\n )\n const data = toAB(enc.encode(`${headerSeg}.${payloadSeg}`))\n const sig = toAB(base64UrlDecode(sigSeg))\n const ok = await crypto.subtle.verify('HMAC', key, sig, data)\n if (!ok) return { valid: false, payload: null, reason: 'bad-signature' }\n\n let payload: JWTPayload\n try {\n payload = decodeJSON<JWTPayload>(payloadSeg)\n } catch {\n return { valid: false, payload: null, reason: 'bad-payload' }\n }\n\n const now = Math.floor(Date.now() / 1000)\n if (payload.exp != null && now >= payload.exp) return { valid: false, payload, reason: 'expired' }\n if (payload.nbf != null && now < payload.nbf) return { valid: false, payload, reason: 'not-yet-valid' }\n\n return { valid: true, payload }\n}\n","/**\n * Edge-safe cookie helpers used by middleware and server helpers.\n * Avoid importing anything React/DOM here.\n */\n\nexport interface CookieOptions {\n path?: string\n maxAge?: number\n domain?: string\n secure?: boolean\n httpOnly?: boolean\n sameSite?: 'lax' | 'strict' | 'none'\n}\n\nexport function serializeCookie(name: string, value: string, opts: CookieOptions = {}): string {\n const parts = [`${name}=${encodeURIComponent(value)}`]\n parts.push(`Path=${opts.path ?? '/'}`)\n if (opts.maxAge != null) parts.push(`Max-Age=${opts.maxAge}`)\n if (opts.domain) parts.push(`Domain=${opts.domain}`)\n if (opts.secure) parts.push('Secure')\n if (opts.httpOnly) parts.push('HttpOnly')\n parts.push(`SameSite=${opts.sameSite ?? 'Lax'}`)\n return parts.join('; ')\n}\n\nexport function parseCookies(header: string | null | undefined): Record<string, string> {\n if (!header) return {}\n const out: Record<string, string> = {}\n for (const part of header.split(';')) {\n const idx = part.indexOf('=')\n if (idx === -1) continue\n const k = part.slice(0, idx).trim()\n const v = part.slice(idx + 1).trim()\n if (k) out[k] = decodeURIComponent(v)\n }\n return out\n}\n\nexport function readCookieFromRequest(req: Request, name: string): string | null {\n return parseCookies(req.headers.get('cookie'))[name] ?? null\n}\n","import type { AdminConfig } from '../../config/types'\nimport type { AuthSession, AuthUser } from '../types'\nimport { verifyJWT } from './verifyJWT'\nimport { parseCookies } from './cookies'\n\nconst DEFAULT_COOKIE = 'admin_kit_token'\n\n/**\n * Server-side session reader. Usable in:\n * - App Router server components (pass `headers()` cookie via `req`)\n * - Route Handlers (pass the Request)\n * - getServerSideProps (build a Request-like from req.headers.cookie)\n *\n * For JWT, this verifies the token with config.auth.jwt.secret.\n * For OAuth/custom, this calls config.auth.custom.getSession() if available,\n * otherwise returns null (consumer should implement their own).\n */\nexport async function getServerSession(\n config: AdminConfig,\n req: Request | { headers: { cookie?: string | null } | Headers },\n): Promise<AuthSession | null> {\n if (config.auth.provider === 'jwt') {\n const jwt = config.auth.jwt\n if (!jwt?.secret) {\n throw new Error('config.auth.jwt.secret is required for getServerSession()')\n }\n const cookieHeader = getCookieHeader(req)\n const cookieName = jwt.cookieName ?? DEFAULT_COOKIE\n const token = parseCookies(cookieHeader)[cookieName]\n if (!token) return null\n const result = await verifyJWT(token, jwt.secret)\n if (!result.valid || !result.payload) return null\n const mapUser = jwt.mapUser ?? ((raw: unknown) => raw as AuthUser)\n return {\n user: mapUser(result.payload),\n accessToken: token,\n expiresAt: result.payload.exp,\n }\n }\n\n if (config.auth.provider === 'custom' && config.auth.custom?.getSession) {\n return config.auth.custom.getSession()\n }\n\n // OAuth: consumer must implement their own callback/session API; we have\n // no token to verify here without server state.\n return null\n}\n\nfunction getCookieHeader(req: Request | { headers: { cookie?: string | null } | Headers }): string | null {\n const headers = req.headers\n if (headers instanceof Headers) return headers.get('cookie')\n return (headers as { cookie?: string | null }).cookie ?? null\n}\n"]}
@@ -0,0 +1,56 @@
1
+ import { A as AdminConfig, g as AuthSession } from './types-N0f4k4Ie.cjs';
2
+ import 'react';
3
+
4
+ /**
5
+ * Server-side session reader. Usable in:
6
+ * - App Router server components (pass `headers()` cookie via `req`)
7
+ * - Route Handlers (pass the Request)
8
+ * - getServerSideProps (build a Request-like from req.headers.cookie)
9
+ *
10
+ * For JWT, this verifies the token with config.auth.jwt.secret.
11
+ * For OAuth/custom, this calls config.auth.custom.getSession() if available,
12
+ * otherwise returns null (consumer should implement their own).
13
+ */
14
+ declare function getServerSession(config: AdminConfig, req: Request | {
15
+ headers: {
16
+ cookie?: string | null;
17
+ } | Headers;
18
+ }): Promise<AuthSession | null>;
19
+
20
+ /**
21
+ * Edge-safe JWT verification using the Web Crypto API.
22
+ * Supports HS256 / HS384 / HS512. For RS-family or ES-family algorithms,
23
+ * plug in `jose` via the `verify` option on createAdminMiddleware
24
+ * (custom verifier).
25
+ */
26
+ interface JWTPayload {
27
+ sub?: string;
28
+ exp?: number;
29
+ iat?: number;
30
+ nbf?: number;
31
+ [key: string]: unknown;
32
+ }
33
+ interface VerifyResult {
34
+ valid: boolean;
35
+ payload: JWTPayload | null;
36
+ reason?: string;
37
+ }
38
+ declare function verifyJWT(token: string, secret: string): Promise<VerifyResult>;
39
+
40
+ /**
41
+ * Edge-safe cookie helpers used by middleware and server helpers.
42
+ * Avoid importing anything React/DOM here.
43
+ */
44
+ interface CookieOptions {
45
+ path?: string;
46
+ maxAge?: number;
47
+ domain?: string;
48
+ secure?: boolean;
49
+ httpOnly?: boolean;
50
+ sameSite?: 'lax' | 'strict' | 'none';
51
+ }
52
+ declare function serializeCookie(name: string, value: string, opts?: CookieOptions): string;
53
+ declare function parseCookies(header: string | null | undefined): Record<string, string>;
54
+ declare function readCookieFromRequest(req: Request, name: string): string | null;
55
+
56
+ export { type CookieOptions, type JWTPayload, type VerifyResult, getServerSession, parseCookies, readCookieFromRequest, serializeCookie, verifyJWT };
@@ -0,0 +1,56 @@
1
+ import { A as AdminConfig, g as AuthSession } from './types-N0f4k4Ie.js';
2
+ import 'react';
3
+
4
+ /**
5
+ * Server-side session reader. Usable in:
6
+ * - App Router server components (pass `headers()` cookie via `req`)
7
+ * - Route Handlers (pass the Request)
8
+ * - getServerSideProps (build a Request-like from req.headers.cookie)
9
+ *
10
+ * For JWT, this verifies the token with config.auth.jwt.secret.
11
+ * For OAuth/custom, this calls config.auth.custom.getSession() if available,
12
+ * otherwise returns null (consumer should implement their own).
13
+ */
14
+ declare function getServerSession(config: AdminConfig, req: Request | {
15
+ headers: {
16
+ cookie?: string | null;
17
+ } | Headers;
18
+ }): Promise<AuthSession | null>;
19
+
20
+ /**
21
+ * Edge-safe JWT verification using the Web Crypto API.
22
+ * Supports HS256 / HS384 / HS512. For RS-family or ES-family algorithms,
23
+ * plug in `jose` via the `verify` option on createAdminMiddleware
24
+ * (custom verifier).
25
+ */
26
+ interface JWTPayload {
27
+ sub?: string;
28
+ exp?: number;
29
+ iat?: number;
30
+ nbf?: number;
31
+ [key: string]: unknown;
32
+ }
33
+ interface VerifyResult {
34
+ valid: boolean;
35
+ payload: JWTPayload | null;
36
+ reason?: string;
37
+ }
38
+ declare function verifyJWT(token: string, secret: string): Promise<VerifyResult>;
39
+
40
+ /**
41
+ * Edge-safe cookie helpers used by middleware and server helpers.
42
+ * Avoid importing anything React/DOM here.
43
+ */
44
+ interface CookieOptions {
45
+ path?: string;
46
+ maxAge?: number;
47
+ domain?: string;
48
+ secure?: boolean;
49
+ httpOnly?: boolean;
50
+ sameSite?: 'lax' | 'strict' | 'none';
51
+ }
52
+ declare function serializeCookie(name: string, value: string, opts?: CookieOptions): string;
53
+ declare function parseCookies(header: string | null | undefined): Record<string, string>;
54
+ declare function readCookieFromRequest(req: Request, name: string): string | null;
55
+
56
+ export { type CookieOptions, type JWTPayload, type VerifyResult, getServerSession, parseCookies, readCookieFromRequest, serializeCookie, verifyJWT };
package/dist/server.js ADDED
@@ -0,0 +1,122 @@
1
+ // src/auth/server/verifyJWT.ts
2
+ var enc = new TextEncoder();
3
+ function toAB(view) {
4
+ const buf = new ArrayBuffer(view.byteLength);
5
+ new Uint8Array(buf).set(view);
6
+ return buf;
7
+ }
8
+ function base64UrlDecode(input) {
9
+ const pad = input.length % 4 === 0 ? "" : "=".repeat(4 - input.length % 4);
10
+ const b64 = (input + pad).replace(/-/g, "+").replace(/_/g, "/");
11
+ const bin = typeof atob === "function" ? atob(b64) : Buffer.from(b64, "base64").toString("binary");
12
+ const out = new Uint8Array(new ArrayBuffer(bin.length));
13
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
14
+ return out;
15
+ }
16
+ function decodeJSON(seg) {
17
+ const bytes = base64UrlDecode(seg);
18
+ const text = new TextDecoder().decode(bytes);
19
+ return JSON.parse(text);
20
+ }
21
+ var ALGS = {
22
+ HS256: { name: "HMAC", hash: "SHA-256" },
23
+ HS384: { name: "HMAC", hash: "SHA-384" },
24
+ HS512: { name: "HMAC", hash: "SHA-512" }
25
+ };
26
+ async function verifyJWT(token, secret) {
27
+ const parts = token.split(".");
28
+ if (parts.length !== 3) return { valid: false, payload: null, reason: "malformed" };
29
+ const [headerSeg, payloadSeg, sigSeg] = parts;
30
+ let header;
31
+ try {
32
+ header = decodeJSON(headerSeg);
33
+ } catch {
34
+ return { valid: false, payload: null, reason: "bad-header" };
35
+ }
36
+ const algSpec = header.alg ? ALGS[header.alg] : void 0;
37
+ if (!algSpec) return { valid: false, payload: null, reason: `unsupported-alg:${header.alg}` };
38
+ const key = await crypto.subtle.importKey(
39
+ "raw",
40
+ toAB(enc.encode(secret)),
41
+ { name: "HMAC", hash: algSpec.hash },
42
+ false,
43
+ ["verify"]
44
+ );
45
+ const data = toAB(enc.encode(`${headerSeg}.${payloadSeg}`));
46
+ const sig = toAB(base64UrlDecode(sigSeg));
47
+ const ok = await crypto.subtle.verify("HMAC", key, sig, data);
48
+ if (!ok) return { valid: false, payload: null, reason: "bad-signature" };
49
+ let payload;
50
+ try {
51
+ payload = decodeJSON(payloadSeg);
52
+ } catch {
53
+ return { valid: false, payload: null, reason: "bad-payload" };
54
+ }
55
+ const now = Math.floor(Date.now() / 1e3);
56
+ if (payload.exp != null && now >= payload.exp) return { valid: false, payload, reason: "expired" };
57
+ if (payload.nbf != null && now < payload.nbf) return { valid: false, payload, reason: "not-yet-valid" };
58
+ return { valid: true, payload };
59
+ }
60
+
61
+ // src/auth/server/cookies.ts
62
+ function serializeCookie(name, value, opts = {}) {
63
+ const parts = [`${name}=${encodeURIComponent(value)}`];
64
+ parts.push(`Path=${opts.path ?? "/"}`);
65
+ if (opts.maxAge != null) parts.push(`Max-Age=${opts.maxAge}`);
66
+ if (opts.domain) parts.push(`Domain=${opts.domain}`);
67
+ if (opts.secure) parts.push("Secure");
68
+ if (opts.httpOnly) parts.push("HttpOnly");
69
+ parts.push(`SameSite=${opts.sameSite ?? "Lax"}`);
70
+ return parts.join("; ");
71
+ }
72
+ function parseCookies(header) {
73
+ if (!header) return {};
74
+ const out = {};
75
+ for (const part of header.split(";")) {
76
+ const idx = part.indexOf("=");
77
+ if (idx === -1) continue;
78
+ const k = part.slice(0, idx).trim();
79
+ const v = part.slice(idx + 1).trim();
80
+ if (k) out[k] = decodeURIComponent(v);
81
+ }
82
+ return out;
83
+ }
84
+ function readCookieFromRequest(req, name) {
85
+ return parseCookies(req.headers.get("cookie"))[name] ?? null;
86
+ }
87
+
88
+ // src/auth/server/getServerSession.ts
89
+ var DEFAULT_COOKIE = "admin_kit_token";
90
+ async function getServerSession(config, req) {
91
+ if (config.auth.provider === "jwt") {
92
+ const jwt = config.auth.jwt;
93
+ if (!jwt?.secret) {
94
+ throw new Error("config.auth.jwt.secret is required for getServerSession()");
95
+ }
96
+ const cookieHeader = getCookieHeader(req);
97
+ const cookieName = jwt.cookieName ?? DEFAULT_COOKIE;
98
+ const token = parseCookies(cookieHeader)[cookieName];
99
+ if (!token) return null;
100
+ const result = await verifyJWT(token, jwt.secret);
101
+ if (!result.valid || !result.payload) return null;
102
+ const mapUser = jwt.mapUser ?? ((raw) => raw);
103
+ return {
104
+ user: mapUser(result.payload),
105
+ accessToken: token,
106
+ expiresAt: result.payload.exp
107
+ };
108
+ }
109
+ if (config.auth.provider === "custom" && config.auth.custom?.getSession) {
110
+ return config.auth.custom.getSession();
111
+ }
112
+ return null;
113
+ }
114
+ function getCookieHeader(req) {
115
+ const headers = req.headers;
116
+ if (headers instanceof Headers) return headers.get("cookie");
117
+ return headers.cookie ?? null;
118
+ }
119
+
120
+ export { getServerSession, parseCookies, readCookieFromRequest, serializeCookie, verifyJWT };
121
+ //# sourceMappingURL=server.js.map
122
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/server/verifyJWT.ts","../src/auth/server/cookies.ts","../src/auth/server/getServerSession.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["/**\n * Edge-safe JWT verification using the Web Crypto API.\n * Supports HS256 / HS384 / HS512. For RS-family or ES-family algorithms,\n * plug in `jose` via the `verify` option on createAdminMiddleware\n * (custom verifier).\n */\n\nconst enc = new TextEncoder()\n\n/**\n * Web Crypto's `BufferSource` requires `Uint8Array<ArrayBuffer>`. Newer TS\n * lib types widen `TextEncoder.encode()` / typed arrays to `ArrayBufferLike`,\n * which leaks `SharedArrayBuffer` into the type. Copy into a fresh ArrayBuffer\n * so the call sites typecheck cleanly without `as` casts.\n */\nfunction toAB(view: Uint8Array): ArrayBuffer {\n const buf = new ArrayBuffer(view.byteLength)\n new Uint8Array(buf).set(view)\n return buf\n}\n\nfunction base64UrlDecode(input: string): Uint8Array<ArrayBuffer> {\n const pad = input.length % 4 === 0 ? '' : '='.repeat(4 - (input.length % 4))\n const b64 = (input + pad).replace(/-/g, '+').replace(/_/g, '/')\n const bin = typeof atob === 'function' ? atob(b64) : Buffer.from(b64, 'base64').toString('binary')\n const out = new Uint8Array(new ArrayBuffer(bin.length))\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nfunction decodeJSON<T>(seg: string): T {\n const bytes = base64UrlDecode(seg)\n const text = new TextDecoder().decode(bytes)\n return JSON.parse(text) as T\n}\n\nconst ALGS: Record<string, { name: 'HMAC'; hash: string }> = {\n HS256: { name: 'HMAC', hash: 'SHA-256' },\n HS384: { name: 'HMAC', hash: 'SHA-384' },\n HS512: { name: 'HMAC', hash: 'SHA-512' },\n}\n\nexport interface JWTPayload {\n sub?: string\n exp?: number\n iat?: number\n nbf?: number\n [key: string]: unknown\n}\n\nexport interface VerifyResult {\n valid: boolean\n payload: JWTPayload | null\n reason?: string\n}\n\nexport async function verifyJWT(token: string, secret: string): Promise<VerifyResult> {\n const parts = token.split('.')\n if (parts.length !== 3) return { valid: false, payload: null, reason: 'malformed' }\n const [headerSeg, payloadSeg, sigSeg] = parts\n let header: { alg?: string; typ?: string }\n try {\n header = decodeJSON<{ alg?: string; typ?: string }>(headerSeg)\n } catch {\n return { valid: false, payload: null, reason: 'bad-header' }\n }\n const algSpec = header.alg ? ALGS[header.alg] : undefined\n if (!algSpec) return { valid: false, payload: null, reason: `unsupported-alg:${header.alg}` }\n\n const key = await crypto.subtle.importKey(\n 'raw',\n toAB(enc.encode(secret)),\n { name: 'HMAC', hash: algSpec.hash },\n false,\n ['verify'],\n )\n const data = toAB(enc.encode(`${headerSeg}.${payloadSeg}`))\n const sig = toAB(base64UrlDecode(sigSeg))\n const ok = await crypto.subtle.verify('HMAC', key, sig, data)\n if (!ok) return { valid: false, payload: null, reason: 'bad-signature' }\n\n let payload: JWTPayload\n try {\n payload = decodeJSON<JWTPayload>(payloadSeg)\n } catch {\n return { valid: false, payload: null, reason: 'bad-payload' }\n }\n\n const now = Math.floor(Date.now() / 1000)\n if (payload.exp != null && now >= payload.exp) return { valid: false, payload, reason: 'expired' }\n if (payload.nbf != null && now < payload.nbf) return { valid: false, payload, reason: 'not-yet-valid' }\n\n return { valid: true, payload }\n}\n","/**\n * Edge-safe cookie helpers used by middleware and server helpers.\n * Avoid importing anything React/DOM here.\n */\n\nexport interface CookieOptions {\n path?: string\n maxAge?: number\n domain?: string\n secure?: boolean\n httpOnly?: boolean\n sameSite?: 'lax' | 'strict' | 'none'\n}\n\nexport function serializeCookie(name: string, value: string, opts: CookieOptions = {}): string {\n const parts = [`${name}=${encodeURIComponent(value)}`]\n parts.push(`Path=${opts.path ?? '/'}`)\n if (opts.maxAge != null) parts.push(`Max-Age=${opts.maxAge}`)\n if (opts.domain) parts.push(`Domain=${opts.domain}`)\n if (opts.secure) parts.push('Secure')\n if (opts.httpOnly) parts.push('HttpOnly')\n parts.push(`SameSite=${opts.sameSite ?? 'Lax'}`)\n return parts.join('; ')\n}\n\nexport function parseCookies(header: string | null | undefined): Record<string, string> {\n if (!header) return {}\n const out: Record<string, string> = {}\n for (const part of header.split(';')) {\n const idx = part.indexOf('=')\n if (idx === -1) continue\n const k = part.slice(0, idx).trim()\n const v = part.slice(idx + 1).trim()\n if (k) out[k] = decodeURIComponent(v)\n }\n return out\n}\n\nexport function readCookieFromRequest(req: Request, name: string): string | null {\n return parseCookies(req.headers.get('cookie'))[name] ?? null\n}\n","import type { AdminConfig } from '../../config/types'\nimport type { AuthSession, AuthUser } from '../types'\nimport { verifyJWT } from './verifyJWT'\nimport { parseCookies } from './cookies'\n\nconst DEFAULT_COOKIE = 'admin_kit_token'\n\n/**\n * Server-side session reader. Usable in:\n * - App Router server components (pass `headers()` cookie via `req`)\n * - Route Handlers (pass the Request)\n * - getServerSideProps (build a Request-like from req.headers.cookie)\n *\n * For JWT, this verifies the token with config.auth.jwt.secret.\n * For OAuth/custom, this calls config.auth.custom.getSession() if available,\n * otherwise returns null (consumer should implement their own).\n */\nexport async function getServerSession(\n config: AdminConfig,\n req: Request | { headers: { cookie?: string | null } | Headers },\n): Promise<AuthSession | null> {\n if (config.auth.provider === 'jwt') {\n const jwt = config.auth.jwt\n if (!jwt?.secret) {\n throw new Error('config.auth.jwt.secret is required for getServerSession()')\n }\n const cookieHeader = getCookieHeader(req)\n const cookieName = jwt.cookieName ?? DEFAULT_COOKIE\n const token = parseCookies(cookieHeader)[cookieName]\n if (!token) return null\n const result = await verifyJWT(token, jwt.secret)\n if (!result.valid || !result.payload) return null\n const mapUser = jwt.mapUser ?? ((raw: unknown) => raw as AuthUser)\n return {\n user: mapUser(result.payload),\n accessToken: token,\n expiresAt: result.payload.exp,\n }\n }\n\n if (config.auth.provider === 'custom' && config.auth.custom?.getSession) {\n return config.auth.custom.getSession()\n }\n\n // OAuth: consumer must implement their own callback/session API; we have\n // no token to verify here without server state.\n return null\n}\n\nfunction getCookieHeader(req: Request | { headers: { cookie?: string | null } | Headers }): string | null {\n const headers = req.headers\n if (headers instanceof Headers) return headers.get('cookie')\n return (headers as { cookie?: string | null }).cookie ?? null\n}\n"]}