@tern-secure/nextjs 5.2.0-canary.v20251008165428 → 5.2.0-canary.v20251019190011
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/cjs/app-router/admin/endpointRouter.js +13 -1
- package/dist/cjs/app-router/admin/endpointRouter.js.map +1 -1
- package/dist/cjs/app-router/admin/sessionHandlers.js +71 -3
- package/dist/cjs/app-router/admin/sessionHandlers.js.map +1 -1
- package/dist/cjs/app-router/admin/types.js +17 -0
- package/dist/cjs/app-router/admin/types.js.map +1 -1
- package/dist/cjs/app-router/client/TernSecureProvider.js +17 -7
- package/dist/cjs/app-router/client/TernSecureProvider.js.map +1 -1
- package/dist/cjs/app-router/server/TernSecureProvider.js +92 -0
- package/dist/cjs/app-router/server/TernSecureProvider.js.map +1 -0
- package/dist/cjs/app-router/server/auth.js +2 -16
- package/dist/cjs/app-router/server/auth.js.map +1 -1
- package/dist/cjs/app-router/server/utils.js +2 -2
- package/dist/cjs/app-router/server/utils.js.map +1 -1
- package/dist/cjs/boundary/NextOptionsCtx.js +52 -0
- package/dist/cjs/boundary/NextOptionsCtx.js.map +1 -0
- package/dist/cjs/boundary/PromiseAuthProvider.js +68 -0
- package/dist/cjs/boundary/PromiseAuthProvider.js.map +1 -0
- package/dist/cjs/boundary/components.js +6 -3
- package/dist/cjs/boundary/components.js.map +1 -1
- package/dist/cjs/index.js +5 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/server/data/getAuthDataFromRequest.js +57 -0
- package/dist/cjs/server/data/getAuthDataFromRequest.js.map +1 -0
- package/dist/cjs/server/index.js +3 -0
- package/dist/cjs/server/index.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils/allNextProviderProps.js +3 -3
- package/dist/cjs/utils/allNextProviderProps.js.map +1 -1
- package/dist/esm/app-router/admin/endpointRouter.js +14 -2
- package/dist/esm/app-router/admin/endpointRouter.js.map +1 -1
- package/dist/esm/app-router/admin/sessionHandlers.js +71 -4
- package/dist/esm/app-router/admin/sessionHandlers.js.map +1 -1
- package/dist/esm/app-router/admin/types.js +16 -0
- package/dist/esm/app-router/admin/types.js.map +1 -1
- package/dist/esm/app-router/client/TernSecureProvider.js +17 -9
- package/dist/esm/app-router/client/TernSecureProvider.js.map +1 -1
- package/dist/esm/app-router/server/TernSecureProvider.js +58 -0
- package/dist/esm/app-router/server/TernSecureProvider.js.map +1 -0
- package/dist/esm/app-router/server/auth.js +2 -21
- package/dist/esm/app-router/server/auth.js.map +1 -1
- package/dist/esm/app-router/server/utils.js +2 -2
- package/dist/esm/app-router/server/utils.js.map +1 -1
- package/dist/esm/boundary/NextOptionsCtx.js +17 -0
- package/dist/esm/boundary/NextOptionsCtx.js.map +1 -0
- package/dist/esm/boundary/PromiseAuthProvider.js +33 -0
- package/dist/esm/boundary/PromiseAuthProvider.js.map +1 -0
- package/dist/esm/boundary/components.js +5 -3
- package/dist/esm/boundary/components.js.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/server/data/getAuthDataFromRequest.js +31 -0
- package/dist/esm/server/data/getAuthDataFromRequest.js.map +1 -0
- package/dist/esm/server/index.js +2 -0
- package/dist/esm/server/index.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/allNextProviderProps.js +3 -3
- package/dist/esm/utils/allNextProviderProps.js.map +1 -1
- package/dist/types/app-router/admin/endpointRouter.d.ts.map +1 -1
- package/dist/types/app-router/admin/sessionHandlers.d.ts +3 -1
- package/dist/types/app-router/admin/sessionHandlers.d.ts.map +1 -1
- package/dist/types/app-router/admin/types.d.ts +2 -1
- package/dist/types/app-router/admin/types.d.ts.map +1 -1
- package/dist/types/app-router/client/TernSecureProvider.d.ts +2 -24
- package/dist/types/app-router/client/TernSecureProvider.d.ts.map +1 -1
- package/dist/types/app-router/server/TernSecureProvider.d.ts +4 -0
- package/dist/types/app-router/server/TernSecureProvider.d.ts.map +1 -0
- package/dist/types/app-router/server/auth.d.ts.map +1 -1
- package/dist/types/boundary/NextOptionsCtx.d.ts +9 -0
- package/dist/types/boundary/NextOptionsCtx.d.ts.map +1 -0
- package/dist/types/boundary/PromiseAuthProvider.d.ts +8 -0
- package/dist/types/boundary/PromiseAuthProvider.d.ts.map +1 -0
- package/dist/types/boundary/components.d.ts +2 -1
- package/dist/types/boundary/components.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/server/data/getAuthDataFromRequest.d.ts +26 -0
- package/dist/types/server/data/getAuthDataFromRequest.d.ts.map +1 -0
- package/dist/types/server/index.d.ts +1 -0
- package/dist/types/server/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/allNextProviderProps.d.ts +1 -4
- package/dist/types/utils/allNextProviderProps.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/cjs/server/edge-session.js +0 -173
- package/dist/cjs/server/edge-session.js.map +0 -1
- package/dist/cjs/server/jwt-edge.js +0 -138
- package/dist/cjs/server/jwt-edge.js.map +0 -1
- package/dist/cjs/server/jwt.js +0 -138
- package/dist/cjs/server/jwt.js.map +0 -1
- package/dist/cjs/server/session-store.js +0 -74
- package/dist/cjs/server/session-store.js.map +0 -1
- package/dist/esm/server/edge-session.js +0 -146
- package/dist/esm/server/edge-session.js.map +0 -1
- package/dist/esm/server/jwt-edge.js +0 -114
- package/dist/esm/server/jwt-edge.js.map +0 -1
- package/dist/esm/server/jwt.js +0 -114
- package/dist/esm/server/jwt.js.map +0 -1
- package/dist/esm/server/session-store.js +0 -49
- package/dist/esm/server/session-store.js.map +0 -1
- package/dist/types/server/edge-session.d.ts +0 -16
- package/dist/types/server/edge-session.d.ts.map +0 -1
- package/dist/types/server/jwt-edge.d.ts +0 -14
- package/dist/types/server/jwt-edge.d.ts.map +0 -1
- package/dist/types/server/jwt.d.ts +0 -14
- package/dist/types/server/jwt.d.ts.map +0 -1
- package/dist/types/server/session-store.d.ts +0 -30
- package/dist/types/server/session-store.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/jwt.ts"],"sourcesContent":["import { createRemoteJWKSet,jwtVerify } from \"jose\";\r\nimport { cache } from \"react\";\r\n\r\ninterface FirebaseIdTokenPayload {\r\n iss: string;\r\n aud: string;\r\n auth_time: number;\r\n user_id: string;\r\n sub: string;\r\n iat: number;\r\n exp: number;\r\n email?: string;\r\n email_verified?: boolean;\r\n firebase: {\r\n identities: {\r\n [key: string]: any;\r\n };\r\n sign_in_provider: string;\r\n tenant?: string;\r\n };\r\n}\r\n\r\ninterface FirebaseTokenResult {\r\n valid: boolean;\r\n tenant?: string;\r\n uid?: string;\r\n email?: string | null;\r\n emailVerified?: boolean;\r\n authTime?: number;\r\n issuedAt?: number;\r\n expiresAt?: number;\r\n error?: string;\r\n}\r\n\r\n// Firebase public key endpoints\r\nconst FIREBASE_ID_TOKEN_URL =\r\n \"https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com\";\r\nconst FIREBASE_SESSION_CERT_URL =\r\n \"https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys\";\r\n\r\n// Cache the JWKS using React cache\r\nconst getIdTokenJWKS = cache(() => {\r\n return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {\r\n cacheMaxAge: 3600000, // 1 hour\r\n timeoutDuration: 5000, // 5 seconds\r\n cooldownDuration: 30000, // 30 seconds between retries\r\n });\r\n});\r\n\r\nconst getSessionJWKS = cache(() => {\r\n return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {\r\n cacheMaxAge: 3600000, // 1 hour\r\n timeoutDuration: 5000, // 5 seconds\r\n cooldownDuration: 30000, // 30 seconds between retries\r\n });\r\n});\r\n\r\n// Helper to decode JWT without verification\r\nfunction decodeJwt(token: string) {\r\n try {\r\n const [headerB64, payloadB64] = token.split(\".\");\r\n const header = JSON.parse(Buffer.from(headerB64, \"base64\").toString());\r\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64\").toString());\r\n return { header, payload };\r\n } catch (error) {\r\n console.error(\"Error decoding JWT:\", error);\r\n return null;\r\n }\r\n}\r\n\r\nexport async function verifyFirebaseToken(\r\n token: string,\r\n isSessionCookie = false\r\n): Promise<FirebaseTokenResult> {\r\n try {\r\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;\r\n if (!projectId) {\r\n throw new Error(\"Firebase Project ID is not configured\");\r\n }\r\n\r\n const decoded = decodeJwt(token);\r\n if (!decoded) {\r\n throw new Error(\"Invalid token format\");\r\n }\r\n\r\n let retries = 3;\r\n let lastError: Error | null = null;\r\n\r\n while (retries > 0) {\r\n try {\r\n // Use different JWKS based on token type\r\n const JWKS = isSessionCookie\r\n ? await getSessionJWKS()\r\n : await getIdTokenJWKS();\r\n\r\n const { payload } = await jwtVerify(token, JWKS, {\r\n issuer: isSessionCookie\r\n ? \"https://session.firebase.google.com/\" + projectId\r\n : \"https://securetoken.google.com/\" + projectId,\r\n audience: projectId,\r\n algorithms: [\"RS256\"],\r\n });\r\n\r\n const firebasePayload = payload as unknown as FirebaseIdTokenPayload;\r\n const now = Math.floor(Date.now() / 1000);\r\n\r\n // Verify token claims\r\n if (firebasePayload.exp <= now) {\r\n throw new Error(\"Token has expired\");\r\n }\r\n\r\n if (firebasePayload.iat > now) {\r\n throw new Error(\"Token issued time is in the future\");\r\n }\r\n\r\n if (!firebasePayload.sub) {\r\n throw new Error(\"Token subject is empty\");\r\n }\r\n\r\n if (firebasePayload.auth_time > now) {\r\n throw new Error(\"Token auth time is in the future\");\r\n }\r\n\r\n return {\r\n valid: true,\r\n uid: firebasePayload.sub,\r\n email: firebasePayload.email,\r\n emailVerified: firebasePayload.email_verified,\r\n tenant: firebasePayload.firebase.tenant,\r\n authTime: firebasePayload.auth_time,\r\n issuedAt: firebasePayload.iat,\r\n expiresAt: firebasePayload.exp,\r\n };\r\n } catch (error) {\r\n lastError = error as Error;\r\n if (error instanceof Error && error.name === \"JWKSNoMatchingKey\") {\r\n console.warn(`JWKS retry attempt ${4 - retries}:`, error.message);\r\n retries--;\r\n if (retries > 0) {\r\n await new Promise((resolve) => setTimeout(resolve, 1000));\r\n continue;\r\n }\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n throw lastError || new Error(\"Failed to verify token after retries\");\r\n } catch (error) {\r\n console.error(\"Token verification details:\", {\r\n error:\r\n error instanceof Error\r\n ? {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack,\r\n }\r\n : error,\r\n decoded: decodeJwt(token),\r\n //projectId,\r\n isSessionCookie,\r\n });\r\n\r\n return {\r\n valid: false,\r\n error: error instanceof Error ? error.message : \"Invalid token\",\r\n };\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6C;AAC7C,mBAAsB;AAkCtB,MAAM,wBACJ;AACF,MAAM,4BACJ;AAGF,MAAM,qBAAiB,oBAAM,MAAM;AACjC,aAAO,gCAAmB,IAAI,IAAI,qBAAqB,GAAG;AAAA,IACxD,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,EACpB,CAAC;AACH,CAAC;AAED,MAAM,qBAAiB,oBAAM,MAAM;AACjC,aAAO,gCAAmB,IAAI,IAAI,yBAAyB,GAAG;AAAA,IAC5D,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,EACpB,CAAC;AACH,CAAC;AAGD,SAAS,UAAU,OAAe;AAChC,MAAI;AACF,UAAM,CAAC,WAAW,UAAU,IAAI,MAAM,MAAM,GAAG;AAC/C,UAAM,SAAS,KAAK,MAAM,OAAO,KAAK,WAAW,QAAQ,EAAE,SAAS,CAAC;AACrE,UAAM,UAAU,KAAK,MAAM,OAAO,KAAK,YAAY,QAAQ,EAAE,SAAS,CAAC;AACvE,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ,MAAM,uBAAuB,KAAK;AAC1C,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,oBACpB,OACA,kBAAkB,OACY;AAC9B,MAAI;AACF,UAAM,YAAY,QAAQ,IAAI;AAC9B,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAEA,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAEA,QAAI,UAAU;AACd,QAAI,YAA0B;AAE9B,WAAO,UAAU,GAAG;AAClB,UAAI;AAEF,cAAM,OAAO,kBACT,MAAM,eAAe,IACrB,MAAM,eAAe;AAEzB,cAAM,EAAE,QAAQ,IAAI,UAAM,uBAAU,OAAO,MAAM;AAAA,UAC/C,QAAQ,kBACJ,yCAAyC,YACzC,oCAAoC;AAAA,UACxC,UAAU;AAAA,UACV,YAAY,CAAC,OAAO;AAAA,QACtB,CAAC;AAED,cAAM,kBAAkB;AACxB,cAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAGxC,YAAI,gBAAgB,OAAO,KAAK;AAC9B,gBAAM,IAAI,MAAM,mBAAmB;AAAA,QACrC;AAEA,YAAI,gBAAgB,MAAM,KAAK;AAC7B,gBAAM,IAAI,MAAM,oCAAoC;AAAA,QACtD;AAEA,YAAI,CAAC,gBAAgB,KAAK;AACxB,gBAAM,IAAI,MAAM,wBAAwB;AAAA,QAC1C;AAEA,YAAI,gBAAgB,YAAY,KAAK;AACnC,gBAAM,IAAI,MAAM,kCAAkC;AAAA,QACpD;AAEA,eAAO;AAAA,UACL,OAAO;AAAA,UACP,KAAK,gBAAgB;AAAA,UACrB,OAAO,gBAAgB;AAAA,UACvB,eAAe,gBAAgB;AAAA,UAC/B,QAAQ,gBAAgB,SAAS;AAAA,UACjC,UAAU,gBAAgB;AAAA,UAC1B,UAAU,gBAAgB;AAAA,UAC1B,WAAW,gBAAgB;AAAA,QAC7B;AAAA,MACF,SAAS,OAAO;AACd,oBAAY;AACZ,YAAI,iBAAiB,SAAS,MAAM,SAAS,qBAAqB;AAChE,kBAAQ,KAAK,sBAAsB,IAAI,OAAO,KAAK,MAAM,OAAO;AAChE;AACA,cAAI,UAAU,GAAG;AACf,kBAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AACxD;AAAA,UACF;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,MAAM,sCAAsC;AAAA,EACrE,SAAS,OAAO;AACd,YAAQ,MAAM,+BAA+B;AAAA,MAC3C,OACE,iBAAiB,QACb;AAAA,QACE,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,OAAO,MAAM;AAAA,MACf,IACA;AAAA,MACN,SAAS,UAAU,KAAK;AAAA;AAAA,MAExB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var session_store_exports = {};
|
|
20
|
-
__export(session_store_exports, {
|
|
21
|
-
getVerifiedUser: () => getVerifiedUser,
|
|
22
|
-
sessionStore: () => sessionStore
|
|
23
|
-
});
|
|
24
|
-
module.exports = __toCommonJS(session_store_exports);
|
|
25
|
-
var import_react = require("react");
|
|
26
|
-
class SessionStore {
|
|
27
|
-
static instance;
|
|
28
|
-
sessions;
|
|
29
|
-
currentSessionId = null;
|
|
30
|
-
constructor() {
|
|
31
|
-
this.sessions = /* @__PURE__ */ new Map();
|
|
32
|
-
}
|
|
33
|
-
static getInstance() {
|
|
34
|
-
if (!SessionStore.instance) {
|
|
35
|
-
SessionStore.instance = new SessionStore();
|
|
36
|
-
}
|
|
37
|
-
return SessionStore.instance;
|
|
38
|
-
}
|
|
39
|
-
setUser(sessionId, user) {
|
|
40
|
-
console.log("SessionStore: Setting user:", { sessionId, user });
|
|
41
|
-
this.sessions.set(sessionId, user);
|
|
42
|
-
this.currentSessionId = sessionId;
|
|
43
|
-
}
|
|
44
|
-
getUser(sessionId) {
|
|
45
|
-
return this.sessions.get(sessionId) || null;
|
|
46
|
-
}
|
|
47
|
-
getCurrentUser() {
|
|
48
|
-
if (!this.currentSessionId) return null;
|
|
49
|
-
return this.sessions.get(this.currentSessionId) || null;
|
|
50
|
-
}
|
|
51
|
-
removeUser(sessionId) {
|
|
52
|
-
this.sessions.delete(sessionId);
|
|
53
|
-
}
|
|
54
|
-
clear() {
|
|
55
|
-
this.sessions.clear();
|
|
56
|
-
}
|
|
57
|
-
debug() {
|
|
58
|
-
return {
|
|
59
|
-
sessionsCount: this.sessions.size,
|
|
60
|
-
currentSessionId: this.currentSessionId,
|
|
61
|
-
sessions: Array.from(this.sessions.entries())
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const sessionStore = SessionStore.getInstance();
|
|
66
|
-
const getVerifiedUser = (0, import_react.cache)((sessionId) => {
|
|
67
|
-
return sessionStore.getUser(sessionId);
|
|
68
|
-
});
|
|
69
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
70
|
-
0 && (module.exports = {
|
|
71
|
-
getVerifiedUser,
|
|
72
|
-
sessionStore
|
|
73
|
-
});
|
|
74
|
-
//# sourceMappingURL=session-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/session-store.ts"],"sourcesContent":["import { cache } from \"react\"\r\n\r\nimport type { User } from \"./types\"\r\n\r\n/**\r\n * Simple in-memory session store\r\n * In a real app, this would be backed by Redis/etc\r\n */\r\nclass SessionStore {\r\n private static instance: SessionStore\r\n private sessions: Map<string, User>\r\n private currentSessionId: string | null = null\r\n\r\n private constructor() {\r\n this.sessions = new Map()\r\n }\r\n\r\n static getInstance(): SessionStore {\r\n if (!SessionStore.instance) {\r\n SessionStore.instance = new SessionStore()\r\n }\r\n return SessionStore.instance\r\n }\r\n\r\n setUser(sessionId: string, user: User) {\r\n console.log(\"SessionStore: Setting user:\", { sessionId, user })\r\n this.sessions.set(sessionId, user)\r\n this.currentSessionId = sessionId\r\n }\r\n\r\n getUser(sessionId: string): User | null {\r\n return this.sessions.get(sessionId) || null\r\n }\r\n\r\n getCurrentUser(): User | null {\r\n if (!this.currentSessionId) return null\r\n return this.sessions.get(this.currentSessionId) || null\r\n }\r\n\r\n removeUser(sessionId: string) {\r\n this.sessions.delete(sessionId)\r\n }\r\n\r\n clear() {\r\n this.sessions.clear()\r\n }\r\n\r\n debug() {\r\n return {\r\n sessionsCount: this.sessions.size,\r\n currentSessionId: this.currentSessionId,\r\n sessions: Array.from(this.sessions.entries())\r\n }\r\n}\r\n}\r\n\r\n// Export singleton instance\r\nexport const sessionStore = SessionStore.getInstance()\r\n\r\n/**\r\n * Cached function to get user from session store\r\n * Uses React cache for SSR optimization\r\n */\r\nexport const getVerifiedUser = cache((sessionId: string): User | null => {\r\n return sessionStore.getUser(sessionId)\r\n})\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsB;AAQtB,MAAM,aAAa;AAAA,EACjB,OAAe;AAAA,EACP;AAAA,EACA,mBAAkC;AAAA,EAElC,cAAc;AACpB,SAAK,WAAW,oBAAI,IAAI;AAAA,EAC1B;AAAA,EAEA,OAAO,cAA4B;AACjC,QAAI,CAAC,aAAa,UAAU;AAC1B,mBAAa,WAAW,IAAI,aAAa;AAAA,IAC3C;AACA,WAAO,aAAa;AAAA,EACtB;AAAA,EAEA,QAAQ,WAAmB,MAAY;AACrC,YAAQ,IAAI,+BAA+B,EAAE,WAAW,KAAK,CAAC;AAC9D,SAAK,SAAS,IAAI,WAAW,IAAI;AACjC,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,QAAQ,WAAgC;AACtC,WAAO,KAAK,SAAS,IAAI,SAAS,KAAK;AAAA,EACzC;AAAA,EAEA,iBAA8B;AAC5B,QAAI,CAAC,KAAK,iBAAkB,QAAO;AACnC,WAAO,KAAK,SAAS,IAAI,KAAK,gBAAgB,KAAK;AAAA,EACrD;AAAA,EAEA,WAAW,WAAmB;AAC5B,SAAK,SAAS,OAAO,SAAS;AAAA,EAChC;AAAA,EAEA,QAAQ;AACN,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA,EAEA,QAAQ;AACN,WAAO;AAAA,MACL,eAAe,KAAK,SAAS;AAAA,MAC7B,kBAAkB,KAAK;AAAA,MACvB,UAAU,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC;AAAA,IAC9C;AAAA,EACJ;AACA;AAGO,MAAM,eAAe,aAAa,YAAY;AAM9C,MAAM,sBAAkB,oBAAM,CAAC,cAAmC;AACvE,SAAO,aAAa,QAAQ,SAAS;AACvC,CAAC;","names":[]}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { verifyFirebaseToken } from "./jwt";
|
|
2
|
-
async function verifySession(request) {
|
|
3
|
-
try {
|
|
4
|
-
const sessionCookie = request.cookies.get("_session_cookie")?.value;
|
|
5
|
-
if (sessionCookie) {
|
|
6
|
-
const result = await verifyFirebaseToken(sessionCookie, true);
|
|
7
|
-
if (result.valid) {
|
|
8
|
-
return {
|
|
9
|
-
isAuthenticated: true,
|
|
10
|
-
user: {
|
|
11
|
-
uid: result.uid ?? "",
|
|
12
|
-
email: result.email || null,
|
|
13
|
-
tenantId: result.tenant || "default",
|
|
14
|
-
emailVerified: result.emailVerified ?? false,
|
|
15
|
-
disabled: false
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return {
|
|
21
|
-
isAuthenticated: false,
|
|
22
|
-
user: null,
|
|
23
|
-
error: "No valid session found"
|
|
24
|
-
};
|
|
25
|
-
} catch (error) {
|
|
26
|
-
console.error("Session verification error:", error);
|
|
27
|
-
return {
|
|
28
|
-
isAuthenticated: false,
|
|
29
|
-
user: null,
|
|
30
|
-
error: error instanceof Error ? error.message : "Session verification failed"
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
async function verifyTokenEdge(idToken) {
|
|
35
|
-
try {
|
|
36
|
-
const response = await fetch(
|
|
37
|
-
`https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${process.env.NEXT_PUBLIC_FIREBASE_API_KEY}`,
|
|
38
|
-
{
|
|
39
|
-
method: "POST",
|
|
40
|
-
headers: {
|
|
41
|
-
"Content-Type": "application/json"
|
|
42
|
-
},
|
|
43
|
-
body: JSON.stringify({ idToken })
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
const data = await response.json();
|
|
47
|
-
console.log("data Token", data);
|
|
48
|
-
if (!response.ok || !data.users?.[0]) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
const user = data.users[0];
|
|
52
|
-
return {
|
|
53
|
-
uid: user.localId,
|
|
54
|
-
email: user.email || null,
|
|
55
|
-
tenantId: user.tenantId || "default",
|
|
56
|
-
disabled: user.disabled || false
|
|
57
|
-
};
|
|
58
|
-
} catch (error) {
|
|
59
|
-
console.error("Token verification error:", error);
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
async function verifySessionEdge(sessionCookie) {
|
|
64
|
-
try {
|
|
65
|
-
const response = await fetch(
|
|
66
|
-
`https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${process.env.NEXT_PUBLIC_FIREBASE_API_KEY}`,
|
|
67
|
-
{
|
|
68
|
-
method: "POST",
|
|
69
|
-
headers: {
|
|
70
|
-
"Content-Type": "application/json",
|
|
71
|
-
Authorization: `Bearer ${sessionCookie}`
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
);
|
|
75
|
-
const data = await response.json();
|
|
76
|
-
console.log("data Session", data);
|
|
77
|
-
if (!response.ok || !data.users?.[0]) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
const user = data.users[0];
|
|
81
|
-
return {
|
|
82
|
-
uid: user.localId,
|
|
83
|
-
email: user.email || null,
|
|
84
|
-
tenantId: user.tenant || "default",
|
|
85
|
-
disabled: user.disabled || false
|
|
86
|
-
};
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.error("Session verification error:", error);
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async function VerifySessionWithRestApi(request) {
|
|
93
|
-
try {
|
|
94
|
-
const sessionCookie = request.cookies.get("_session_cookie")?.value;
|
|
95
|
-
if (sessionCookie) {
|
|
96
|
-
const response = await fetch(
|
|
97
|
-
`https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${process.env.GOOGLE_CLIENT_ID}`,
|
|
98
|
-
{
|
|
99
|
-
method: "POST",
|
|
100
|
-
headers: {
|
|
101
|
-
"Content-Type": "application/json",
|
|
102
|
-
Authorization: `Bearer ${sessionCookie}`
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
const data = await response.json();
|
|
107
|
-
console.log("[edge-session] data with session cookie", data);
|
|
108
|
-
if (response.ok && data.users?.[0]) {
|
|
109
|
-
const user = data.users[0];
|
|
110
|
-
return {
|
|
111
|
-
isAuthenticated: true,
|
|
112
|
-
user: {
|
|
113
|
-
uid: user.localId,
|
|
114
|
-
email: user.email || null,
|
|
115
|
-
tenantId: user.tenantId || "default",
|
|
116
|
-
emailVerified: user.emailVerified ?? false,
|
|
117
|
-
disabled: user.disabled || false
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
console.log(
|
|
122
|
-
"Session cookie verification failed:",
|
|
123
|
-
data.error?.message || "Invalid session"
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
isAuthenticated: false,
|
|
128
|
-
user: null,
|
|
129
|
-
error: "No valid session found"
|
|
130
|
-
};
|
|
131
|
-
} catch (error) {
|
|
132
|
-
console.error("Session verification error:", error);
|
|
133
|
-
return {
|
|
134
|
-
isAuthenticated: false,
|
|
135
|
-
user: null,
|
|
136
|
-
error: error instanceof Error ? error.message : "Session verification failed"
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
export {
|
|
141
|
-
VerifySessionWithRestApi,
|
|
142
|
-
verifySession,
|
|
143
|
-
verifySessionEdge,
|
|
144
|
-
verifyTokenEdge
|
|
145
|
-
};
|
|
146
|
-
//# sourceMappingURL=edge-session.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/edge-session.ts"],"sourcesContent":["import type { NextRequest } from \"next/server\";\r\n\r\nimport { verifyFirebaseToken } from \"./jwt\";\r\nimport type { BaseUser,SessionResult } from \"./types\";\r\n\r\nexport async function verifySession(\r\n request: NextRequest\r\n): Promise<SessionResult> {\r\n try {\r\n const sessionCookie = request.cookies.get(\"_session_cookie\")?.value;\r\n if (sessionCookie) {\r\n const result = await verifyFirebaseToken(sessionCookie, true);\r\n if (result.valid) {\r\n return {\r\n isAuthenticated: true,\r\n user: {\r\n uid: result.uid ?? \"\",\r\n email: result.email || null,\r\n tenantId: result.tenant || \"default\",\r\n emailVerified: result.emailVerified ?? false,\r\n disabled: false,\r\n },\r\n };\r\n }\r\n }\r\n return {\r\n isAuthenticated: false,\r\n user: null,\r\n error: \"No valid session found\",\r\n };\r\n } catch (error) {\r\n console.error(\"Session verification error:\", error);\r\n return {\r\n isAuthenticated: false,\r\n user: null,\r\n error:\r\n error instanceof Error ? error.message : \"Session verification failed\",\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Edge-compatible token verification using Firebase Auth REST API\r\n */\r\nexport async function verifyTokenEdge(\r\n idToken: string\r\n): Promise<BaseUser | null> {\r\n try {\r\n const response = await fetch(\r\n `https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${process.env.NEXT_PUBLIC_FIREBASE_API_KEY}`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify({ idToken }),\r\n }\r\n );\r\n\r\n const data = await response.json();\r\n console.log(\"data Token\", data);\r\n\r\n if (!response.ok || !data.users?.[0]) {\r\n return null;\r\n }\r\n\r\n const user = data.users[0];\r\n return {\r\n uid: user.localId,\r\n email: user.email || null,\r\n tenantId: user.tenantId || \"default\",\r\n disabled: user.disabled || false,\r\n };\r\n } catch (error) {\r\n console.error(\"Token verification error:\", error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Edge-compatible session cookie verification\r\n */\r\nexport async function verifySessionEdge(\r\n sessionCookie: string\r\n): Promise<BaseUser | null> {\r\n try {\r\n const response = await fetch(\r\n `https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${process.env.NEXT_PUBLIC_FIREBASE_API_KEY}`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${sessionCookie}`,\r\n },\r\n }\r\n );\r\n\r\n const data = await response.json();\r\n console.log(\"data Session\", data);\r\n\r\n if (!response.ok || !data.users?.[0]) {\r\n return null;\r\n }\r\n\r\n const user = data.users[0];\r\n return {\r\n uid: user.localId,\r\n email: user.email || null,\r\n tenantId: user.tenant || \"default\",\r\n disabled: user.disabled || false,\r\n };\r\n } catch (error) {\r\n console.error(\"Session verification error:\", error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Edge-compatible session verification using Firebase Auth REST API\r\n */\r\nexport async function VerifySessionWithRestApi(\r\n request: NextRequest\r\n): Promise<SessionResult> {\r\n try {\r\n // First try session cookie\r\n const sessionCookie = request.cookies.get(\"_session_cookie\")?.value;\r\n if (sessionCookie) {\r\n const response = await fetch(\r\n `https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${process.env.GOOGLE_CLIENT_ID}`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${sessionCookie}`,\r\n },\r\n }\r\n );\r\n\r\n const data = await response.json();\r\n console.log(\"[edge-session] data with session cookie\", data);\r\n\r\n if (response.ok && data.users?.[0]) {\r\n const user = data.users[0];\r\n return {\r\n isAuthenticated: true,\r\n user: {\r\n uid: user.localId,\r\n email: user.email || null,\r\n tenantId: user.tenantId || \"default\",\r\n emailVerified: user.emailVerified ?? false,\r\n disabled: user.disabled || false,\r\n },\r\n };\r\n }\r\n console.log(\r\n \"Session cookie verification failed:\",\r\n data.error?.message || \"Invalid session\"\r\n );\r\n }\r\n return {\r\n isAuthenticated: false,\r\n user: null,\r\n error: \"No valid session found\",\r\n };\r\n } catch (error) {\r\n console.error(\"Session verification error:\", error);\r\n return {\r\n isAuthenticated: false,\r\n user: null,\r\n error:\r\n error instanceof Error ? error.message : \"Session verification failed\",\r\n };\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
2
|
-
import { cache } from "react";
|
|
3
|
-
const FIREBASE_ID_TOKEN_URL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";
|
|
4
|
-
const FIREBASE_SESSION_CERT_URL = "https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys";
|
|
5
|
-
const getIdTokenJWKS = cache(() => {
|
|
6
|
-
return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {
|
|
7
|
-
cacheMaxAge: 36e5,
|
|
8
|
-
// 1 hour
|
|
9
|
-
timeoutDuration: 5e3,
|
|
10
|
-
// 5 seconds
|
|
11
|
-
cooldownDuration: 3e4
|
|
12
|
-
// 30 seconds between retries
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
const getSessionJWKS = cache(() => {
|
|
16
|
-
return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {
|
|
17
|
-
cacheMaxAge: 36e5,
|
|
18
|
-
// 1 hour
|
|
19
|
-
timeoutDuration: 5e3,
|
|
20
|
-
// 5 seconds
|
|
21
|
-
cooldownDuration: 3e4
|
|
22
|
-
// 30 seconds between retries
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
function decodeJwt(token) {
|
|
26
|
-
try {
|
|
27
|
-
const [headerB64, payloadB64] = token.split(".");
|
|
28
|
-
const header = JSON.parse(Buffer.from(headerB64, "base64").toString());
|
|
29
|
-
const payload = JSON.parse(Buffer.from(payloadB64, "base64").toString());
|
|
30
|
-
return { header, payload };
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error("Error decoding JWT:", error);
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async function verifyFirebaseToken(token, isSessionCookie = false) {
|
|
37
|
-
try {
|
|
38
|
-
const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;
|
|
39
|
-
if (!projectId) {
|
|
40
|
-
throw new Error("Firebase Project ID is not configured");
|
|
41
|
-
}
|
|
42
|
-
const decoded = decodeJwt(token);
|
|
43
|
-
if (!decoded) {
|
|
44
|
-
throw new Error("Invalid token format");
|
|
45
|
-
}
|
|
46
|
-
let retries = 3;
|
|
47
|
-
let lastError = null;
|
|
48
|
-
while (retries > 0) {
|
|
49
|
-
try {
|
|
50
|
-
const JWKS = isSessionCookie ? await getSessionJWKS() : await getIdTokenJWKS();
|
|
51
|
-
const { payload } = await jwtVerify(token, JWKS, {
|
|
52
|
-
issuer: isSessionCookie ? "https://session.firebase.google.com/" + projectId : "https://securetoken.google.com/" + projectId,
|
|
53
|
-
audience: projectId,
|
|
54
|
-
algorithms: ["RS256"]
|
|
55
|
-
});
|
|
56
|
-
const firebasePayload = payload;
|
|
57
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
58
|
-
if (firebasePayload.exp <= now) {
|
|
59
|
-
throw new Error("Token has expired");
|
|
60
|
-
}
|
|
61
|
-
if (firebasePayload.iat > now) {
|
|
62
|
-
throw new Error("Token issued time is in the future");
|
|
63
|
-
}
|
|
64
|
-
if (!firebasePayload.sub) {
|
|
65
|
-
throw new Error("Token subject is empty");
|
|
66
|
-
}
|
|
67
|
-
if (firebasePayload.auth_time > now) {
|
|
68
|
-
throw new Error("Token auth time is in the future");
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
valid: true,
|
|
72
|
-
uid: firebasePayload.sub,
|
|
73
|
-
email: firebasePayload.email,
|
|
74
|
-
emailVerified: firebasePayload.email_verified,
|
|
75
|
-
tenant: firebasePayload.firebase.tenant,
|
|
76
|
-
authTime: firebasePayload.auth_time,
|
|
77
|
-
issuedAt: firebasePayload.iat,
|
|
78
|
-
expiresAt: firebasePayload.exp
|
|
79
|
-
};
|
|
80
|
-
} catch (error) {
|
|
81
|
-
lastError = error;
|
|
82
|
-
if (error instanceof Error && error.name === "JWKSNoMatchingKey") {
|
|
83
|
-
console.warn(`JWKS retry attempt ${4 - retries}:`, error.message);
|
|
84
|
-
retries--;
|
|
85
|
-
if (retries > 0) {
|
|
86
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
throw error;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
throw lastError || new Error("Failed to verify token after retries");
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error("Token verification details:", {
|
|
96
|
-
error: error instanceof Error ? {
|
|
97
|
-
name: error.name,
|
|
98
|
-
message: error.message,
|
|
99
|
-
stack: error.stack
|
|
100
|
-
} : error,
|
|
101
|
-
decoded: decodeJwt(token),
|
|
102
|
-
//projectId,
|
|
103
|
-
isSessionCookie
|
|
104
|
-
});
|
|
105
|
-
return {
|
|
106
|
-
valid: false,
|
|
107
|
-
error: error instanceof Error ? error.message : "Invalid token"
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
export {
|
|
112
|
-
verifyFirebaseToken
|
|
113
|
-
};
|
|
114
|
-
//# sourceMappingURL=jwt-edge.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/jwt-edge.ts"],"sourcesContent":["import { createRemoteJWKSet,jwtVerify } from \"jose\"\r\nimport { cache } from \"react\"\r\n\r\ninterface FirebaseIdTokenPayload {\r\n iss: string\r\n aud: string\r\n auth_time: number\r\n user_id: string\r\n sub: string\r\n iat: number\r\n exp: number\r\n email?: string\r\n email_verified?: boolean\r\n firebase: {\r\n identities: {\r\n [key: string]: any\r\n }\r\n sign_in_provider: string\r\n tenant?: string;\r\n }\r\n}\r\n\r\ninterface FirebaseTokenResult {\r\n valid: boolean;\r\n tenant?: string;\r\n uid?: string;\r\n email?: string | null;\r\n emailVerified?: boolean;\r\n authTime?: number;\r\n issuedAt?: number;\r\n expiresAt?: number;\r\n error?: string;\r\n}\r\n\r\n// Firebase public key endpoints\r\nconst FIREBASE_ID_TOKEN_URL = \"https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com\"\r\nconst FIREBASE_SESSION_CERT_URL = \"https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys\"\r\n\r\n// Cache the JWKS using React cache\r\nconst getIdTokenJWKS = cache(() => {\r\n return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {\r\n cacheMaxAge: 3600000, // 1 hour\r\n timeoutDuration: 5000, // 5 seconds\r\n cooldownDuration: 30000, // 30 seconds between retries\r\n })\r\n})\r\n\r\nconst getSessionJWKS = cache(() => {\r\n return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {\r\n cacheMaxAge: 3600000, // 1 hour\r\n timeoutDuration: 5000, // 5 seconds\r\n cooldownDuration: 30000, // 30 seconds between retries\r\n })\r\n})\r\n\r\n// Helper to decode JWT without verification\r\nfunction decodeJwt(token: string) {\r\n try {\r\n const [headerB64, payloadB64] = token.split(\".\")\r\n const header = JSON.parse(Buffer.from(headerB64, \"base64\").toString())\r\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64\").toString())\r\n return { header, payload }\r\n } catch (error) {\r\n console.error(\"Error decoding JWT:\", error)\r\n return null\r\n }\r\n}\r\n\r\nexport async function verifyFirebaseToken(token: string, isSessionCookie = false): Promise<FirebaseTokenResult> {\r\n try {\r\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID\r\n if (!projectId) {\r\n throw new Error(\"Firebase Project ID is not configured\")\r\n }\r\n\r\n // Decode token for debugging and type checking\r\n const decoded = decodeJwt(token)\r\n if (!decoded) {\r\n throw new Error(\"Invalid token format\")\r\n }\r\n\r\n //console.log(\"Token details:\", {\r\n // header: decoded.header,\r\n // type: isSessionCookie ? \"session_cookie\" : \"id_token\",\r\n //})\r\n\r\n let retries = 3\r\n let lastError: Error | null = null\r\n\r\n while (retries > 0) {\r\n try {\r\n // Use different JWKS based on token type\r\n const JWKS = isSessionCookie ? await getSessionJWKS() : await getIdTokenJWKS()\r\n\r\n const { payload } = await jwtVerify(token, JWKS, {\r\n issuer: isSessionCookie\r\n ? \"https://session.firebase.google.com/\" + projectId\r\n : \"https://securetoken.google.com/\" + projectId,\r\n audience: projectId,\r\n algorithms: [\"RS256\"],\r\n })\r\n\r\n const firebasePayload = payload as unknown as FirebaseIdTokenPayload\r\n const now = Math.floor(Date.now() / 1000)\r\n\r\n // Verify token claims\r\n if (firebasePayload.exp <= now) {\r\n throw new Error(\"Token has expired\")\r\n }\r\n\r\n if (firebasePayload.iat > now) {\r\n throw new Error(\"Token issued time is in the future\")\r\n }\r\n\r\n if (!firebasePayload.sub) {\r\n throw new Error(\"Token subject is empty\")\r\n }\r\n\r\n if (firebasePayload.auth_time > now) {\r\n throw new Error(\"Token auth time is in the future\")\r\n }\r\n\r\n return {\r\n valid: true,\r\n uid: firebasePayload.sub,\r\n email: firebasePayload.email,\r\n emailVerified: firebasePayload.email_verified,\r\n tenant: firebasePayload.firebase.tenant,\r\n authTime: firebasePayload.auth_time,\r\n issuedAt: firebasePayload.iat,\r\n expiresAt: firebasePayload.exp,\r\n }\r\n } catch (error) {\r\n lastError = error as Error\r\n if (error instanceof Error && error.name === \"JWKSNoMatchingKey\") {\r\n console.warn(`JWKS retry attempt ${4 - retries}:`, error.message)\r\n retries--\r\n if (retries > 0) {\r\n await new Promise((resolve) => setTimeout(resolve, 1000))\r\n continue\r\n }\r\n }\r\n throw error\r\n }\r\n }\r\n\r\n throw lastError || new Error(\"Failed to verify token after retries\")\r\n } catch (error) {\r\n console.error(\"Token verification details:\", {\r\n error:\r\n error instanceof Error\r\n ? {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack,\r\n }\r\n : error,\r\n decoded: decodeJwt(token),\r\n //projectId,\r\n isSessionCookie,\r\n })\r\n\r\n return {\r\n valid: false,\r\n error: error instanceof Error ? error.message : \"Invalid token\",\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/esm/server/jwt.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
2
|
-
import { cache } from "react";
|
|
3
|
-
const FIREBASE_ID_TOKEN_URL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";
|
|
4
|
-
const FIREBASE_SESSION_CERT_URL = "https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys";
|
|
5
|
-
const getIdTokenJWKS = cache(() => {
|
|
6
|
-
return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {
|
|
7
|
-
cacheMaxAge: 36e5,
|
|
8
|
-
// 1 hour
|
|
9
|
-
timeoutDuration: 5e3,
|
|
10
|
-
// 5 seconds
|
|
11
|
-
cooldownDuration: 3e4
|
|
12
|
-
// 30 seconds between retries
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
const getSessionJWKS = cache(() => {
|
|
16
|
-
return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {
|
|
17
|
-
cacheMaxAge: 36e5,
|
|
18
|
-
// 1 hour
|
|
19
|
-
timeoutDuration: 5e3,
|
|
20
|
-
// 5 seconds
|
|
21
|
-
cooldownDuration: 3e4
|
|
22
|
-
// 30 seconds between retries
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
function decodeJwt(token) {
|
|
26
|
-
try {
|
|
27
|
-
const [headerB64, payloadB64] = token.split(".");
|
|
28
|
-
const header = JSON.parse(Buffer.from(headerB64, "base64").toString());
|
|
29
|
-
const payload = JSON.parse(Buffer.from(payloadB64, "base64").toString());
|
|
30
|
-
return { header, payload };
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error("Error decoding JWT:", error);
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async function verifyFirebaseToken(token, isSessionCookie = false) {
|
|
37
|
-
try {
|
|
38
|
-
const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;
|
|
39
|
-
if (!projectId) {
|
|
40
|
-
throw new Error("Firebase Project ID is not configured");
|
|
41
|
-
}
|
|
42
|
-
const decoded = decodeJwt(token);
|
|
43
|
-
if (!decoded) {
|
|
44
|
-
throw new Error("Invalid token format");
|
|
45
|
-
}
|
|
46
|
-
let retries = 3;
|
|
47
|
-
let lastError = null;
|
|
48
|
-
while (retries > 0) {
|
|
49
|
-
try {
|
|
50
|
-
const JWKS = isSessionCookie ? await getSessionJWKS() : await getIdTokenJWKS();
|
|
51
|
-
const { payload } = await jwtVerify(token, JWKS, {
|
|
52
|
-
issuer: isSessionCookie ? "https://session.firebase.google.com/" + projectId : "https://securetoken.google.com/" + projectId,
|
|
53
|
-
audience: projectId,
|
|
54
|
-
algorithms: ["RS256"]
|
|
55
|
-
});
|
|
56
|
-
const firebasePayload = payload;
|
|
57
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
58
|
-
if (firebasePayload.exp <= now) {
|
|
59
|
-
throw new Error("Token has expired");
|
|
60
|
-
}
|
|
61
|
-
if (firebasePayload.iat > now) {
|
|
62
|
-
throw new Error("Token issued time is in the future");
|
|
63
|
-
}
|
|
64
|
-
if (!firebasePayload.sub) {
|
|
65
|
-
throw new Error("Token subject is empty");
|
|
66
|
-
}
|
|
67
|
-
if (firebasePayload.auth_time > now) {
|
|
68
|
-
throw new Error("Token auth time is in the future");
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
valid: true,
|
|
72
|
-
uid: firebasePayload.sub,
|
|
73
|
-
email: firebasePayload.email,
|
|
74
|
-
emailVerified: firebasePayload.email_verified,
|
|
75
|
-
tenant: firebasePayload.firebase.tenant,
|
|
76
|
-
authTime: firebasePayload.auth_time,
|
|
77
|
-
issuedAt: firebasePayload.iat,
|
|
78
|
-
expiresAt: firebasePayload.exp
|
|
79
|
-
};
|
|
80
|
-
} catch (error) {
|
|
81
|
-
lastError = error;
|
|
82
|
-
if (error instanceof Error && error.name === "JWKSNoMatchingKey") {
|
|
83
|
-
console.warn(`JWKS retry attempt ${4 - retries}:`, error.message);
|
|
84
|
-
retries--;
|
|
85
|
-
if (retries > 0) {
|
|
86
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
throw error;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
throw lastError || new Error("Failed to verify token after retries");
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error("Token verification details:", {
|
|
96
|
-
error: error instanceof Error ? {
|
|
97
|
-
name: error.name,
|
|
98
|
-
message: error.message,
|
|
99
|
-
stack: error.stack
|
|
100
|
-
} : error,
|
|
101
|
-
decoded: decodeJwt(token),
|
|
102
|
-
//projectId,
|
|
103
|
-
isSessionCookie
|
|
104
|
-
});
|
|
105
|
-
return {
|
|
106
|
-
valid: false,
|
|
107
|
-
error: error instanceof Error ? error.message : "Invalid token"
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
export {
|
|
112
|
-
verifyFirebaseToken
|
|
113
|
-
};
|
|
114
|
-
//# sourceMappingURL=jwt.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/jwt.ts"],"sourcesContent":["import { createRemoteJWKSet,jwtVerify } from \"jose\";\r\nimport { cache } from \"react\";\r\n\r\ninterface FirebaseIdTokenPayload {\r\n iss: string;\r\n aud: string;\r\n auth_time: number;\r\n user_id: string;\r\n sub: string;\r\n iat: number;\r\n exp: number;\r\n email?: string;\r\n email_verified?: boolean;\r\n firebase: {\r\n identities: {\r\n [key: string]: any;\r\n };\r\n sign_in_provider: string;\r\n tenant?: string;\r\n };\r\n}\r\n\r\ninterface FirebaseTokenResult {\r\n valid: boolean;\r\n tenant?: string;\r\n uid?: string;\r\n email?: string | null;\r\n emailVerified?: boolean;\r\n authTime?: number;\r\n issuedAt?: number;\r\n expiresAt?: number;\r\n error?: string;\r\n}\r\n\r\n// Firebase public key endpoints\r\nconst FIREBASE_ID_TOKEN_URL =\r\n \"https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com\";\r\nconst FIREBASE_SESSION_CERT_URL =\r\n \"https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys\";\r\n\r\n// Cache the JWKS using React cache\r\nconst getIdTokenJWKS = cache(() => {\r\n return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {\r\n cacheMaxAge: 3600000, // 1 hour\r\n timeoutDuration: 5000, // 5 seconds\r\n cooldownDuration: 30000, // 30 seconds between retries\r\n });\r\n});\r\n\r\nconst getSessionJWKS = cache(() => {\r\n return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {\r\n cacheMaxAge: 3600000, // 1 hour\r\n timeoutDuration: 5000, // 5 seconds\r\n cooldownDuration: 30000, // 30 seconds between retries\r\n });\r\n});\r\n\r\n// Helper to decode JWT without verification\r\nfunction decodeJwt(token: string) {\r\n try {\r\n const [headerB64, payloadB64] = token.split(\".\");\r\n const header = JSON.parse(Buffer.from(headerB64, \"base64\").toString());\r\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64\").toString());\r\n return { header, payload };\r\n } catch (error) {\r\n console.error(\"Error decoding JWT:\", error);\r\n return null;\r\n }\r\n}\r\n\r\nexport async function verifyFirebaseToken(\r\n token: string,\r\n isSessionCookie = false\r\n): Promise<FirebaseTokenResult> {\r\n try {\r\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;\r\n if (!projectId) {\r\n throw new Error(\"Firebase Project ID is not configured\");\r\n }\r\n\r\n const decoded = decodeJwt(token);\r\n if (!decoded) {\r\n throw new Error(\"Invalid token format\");\r\n }\r\n\r\n let retries = 3;\r\n let lastError: Error | null = null;\r\n\r\n while (retries > 0) {\r\n try {\r\n // Use different JWKS based on token type\r\n const JWKS = isSessionCookie\r\n ? await getSessionJWKS()\r\n : await getIdTokenJWKS();\r\n\r\n const { payload } = await jwtVerify(token, JWKS, {\r\n issuer: isSessionCookie\r\n ? \"https://session.firebase.google.com/\" + projectId\r\n : \"https://securetoken.google.com/\" + projectId,\r\n audience: projectId,\r\n algorithms: [\"RS256\"],\r\n });\r\n\r\n const firebasePayload = payload as unknown as FirebaseIdTokenPayload;\r\n const now = Math.floor(Date.now() / 1000);\r\n\r\n // Verify token claims\r\n if (firebasePayload.exp <= now) {\r\n throw new Error(\"Token has expired\");\r\n }\r\n\r\n if (firebasePayload.iat > now) {\r\n throw new Error(\"Token issued time is in the future\");\r\n }\r\n\r\n if (!firebasePayload.sub) {\r\n throw new Error(\"Token subject is empty\");\r\n }\r\n\r\n if (firebasePayload.auth_time > now) {\r\n throw new Error(\"Token auth time is in the future\");\r\n }\r\n\r\n return {\r\n valid: true,\r\n uid: firebasePayload.sub,\r\n email: firebasePayload.email,\r\n emailVerified: firebasePayload.email_verified,\r\n tenant: firebasePayload.firebase.tenant,\r\n authTime: firebasePayload.auth_time,\r\n issuedAt: firebasePayload.iat,\r\n expiresAt: firebasePayload.exp,\r\n };\r\n } catch (error) {\r\n lastError = error as Error;\r\n if (error instanceof Error && error.name === \"JWKSNoMatchingKey\") {\r\n console.warn(`JWKS retry attempt ${4 - retries}:`, error.message);\r\n retries--;\r\n if (retries > 0) {\r\n await new Promise((resolve) => setTimeout(resolve, 1000));\r\n continue;\r\n }\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n throw lastError || new Error(\"Failed to verify token after retries\");\r\n } catch (error) {\r\n console.error(\"Token verification details:\", {\r\n error:\r\n error instanceof Error\r\n ? {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack,\r\n }\r\n : error,\r\n decoded: decodeJwt(token),\r\n //projectId,\r\n isSessionCookie,\r\n });\r\n\r\n return {\r\n valid: false,\r\n error: error instanceof Error ? error.message : \"Invalid token\",\r\n };\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { cache } from "react";
|
|
2
|
-
class SessionStore {
|
|
3
|
-
static instance;
|
|
4
|
-
sessions;
|
|
5
|
-
currentSessionId = null;
|
|
6
|
-
constructor() {
|
|
7
|
-
this.sessions = /* @__PURE__ */ new Map();
|
|
8
|
-
}
|
|
9
|
-
static getInstance() {
|
|
10
|
-
if (!SessionStore.instance) {
|
|
11
|
-
SessionStore.instance = new SessionStore();
|
|
12
|
-
}
|
|
13
|
-
return SessionStore.instance;
|
|
14
|
-
}
|
|
15
|
-
setUser(sessionId, user) {
|
|
16
|
-
console.log("SessionStore: Setting user:", { sessionId, user });
|
|
17
|
-
this.sessions.set(sessionId, user);
|
|
18
|
-
this.currentSessionId = sessionId;
|
|
19
|
-
}
|
|
20
|
-
getUser(sessionId) {
|
|
21
|
-
return this.sessions.get(sessionId) || null;
|
|
22
|
-
}
|
|
23
|
-
getCurrentUser() {
|
|
24
|
-
if (!this.currentSessionId) return null;
|
|
25
|
-
return this.sessions.get(this.currentSessionId) || null;
|
|
26
|
-
}
|
|
27
|
-
removeUser(sessionId) {
|
|
28
|
-
this.sessions.delete(sessionId);
|
|
29
|
-
}
|
|
30
|
-
clear() {
|
|
31
|
-
this.sessions.clear();
|
|
32
|
-
}
|
|
33
|
-
debug() {
|
|
34
|
-
return {
|
|
35
|
-
sessionsCount: this.sessions.size,
|
|
36
|
-
currentSessionId: this.currentSessionId,
|
|
37
|
-
sessions: Array.from(this.sessions.entries())
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
const sessionStore = SessionStore.getInstance();
|
|
42
|
-
const getVerifiedUser = cache((sessionId) => {
|
|
43
|
-
return sessionStore.getUser(sessionId);
|
|
44
|
-
});
|
|
45
|
-
export {
|
|
46
|
-
getVerifiedUser,
|
|
47
|
-
sessionStore
|
|
48
|
-
};
|
|
49
|
-
//# sourceMappingURL=session-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/session-store.ts"],"sourcesContent":["import { cache } from \"react\"\r\n\r\nimport type { User } from \"./types\"\r\n\r\n/**\r\n * Simple in-memory session store\r\n * In a real app, this would be backed by Redis/etc\r\n */\r\nclass SessionStore {\r\n private static instance: SessionStore\r\n private sessions: Map<string, User>\r\n private currentSessionId: string | null = null\r\n\r\n private constructor() {\r\n this.sessions = new Map()\r\n }\r\n\r\n static getInstance(): SessionStore {\r\n if (!SessionStore.instance) {\r\n SessionStore.instance = new SessionStore()\r\n }\r\n return SessionStore.instance\r\n }\r\n\r\n setUser(sessionId: string, user: User) {\r\n console.log(\"SessionStore: Setting user:\", { sessionId, user })\r\n this.sessions.set(sessionId, user)\r\n this.currentSessionId = sessionId\r\n }\r\n\r\n getUser(sessionId: string): User | null {\r\n return this.sessions.get(sessionId) || null\r\n }\r\n\r\n getCurrentUser(): User | null {\r\n if (!this.currentSessionId) return null\r\n return this.sessions.get(this.currentSessionId) || null\r\n }\r\n\r\n removeUser(sessionId: string) {\r\n this.sessions.delete(sessionId)\r\n }\r\n\r\n clear() {\r\n this.sessions.clear()\r\n }\r\n\r\n debug() {\r\n return {\r\n sessionsCount: this.sessions.size,\r\n currentSessionId: this.currentSessionId,\r\n sessions: Array.from(this.sessions.entries())\r\n }\r\n}\r\n}\r\n\r\n// Export singleton instance\r\nexport const sessionStore = SessionStore.getInstance()\r\n\r\n/**\r\n * Cached function to get user from session store\r\n * Uses React cache for SSR optimization\r\n */\r\nexport const getVerifiedUser = cache((sessionId: string): User | null => {\r\n return sessionStore.getUser(sessionId)\r\n})\r\n\r\n"],"mappings":"AAAA,SAAS,aAAa;AAQtB,MAAM,aAAa;AAAA,EACjB,OAAe;AAAA,EACP;AAAA,EACA,mBAAkC;AAAA,EAElC,cAAc;AACpB,SAAK,WAAW,oBAAI,IAAI;AAAA,EAC1B;AAAA,EAEA,OAAO,cAA4B;AACjC,QAAI,CAAC,aAAa,UAAU;AAC1B,mBAAa,WAAW,IAAI,aAAa;AAAA,IAC3C;AACA,WAAO,aAAa;AAAA,EACtB;AAAA,EAEA,QAAQ,WAAmB,MAAY;AACrC,YAAQ,IAAI,+BAA+B,EAAE,WAAW,KAAK,CAAC;AAC9D,SAAK,SAAS,IAAI,WAAW,IAAI;AACjC,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,QAAQ,WAAgC;AACtC,WAAO,KAAK,SAAS,IAAI,SAAS,KAAK;AAAA,EACzC;AAAA,EAEA,iBAA8B;AAC5B,QAAI,CAAC,KAAK,iBAAkB,QAAO;AACnC,WAAO,KAAK,SAAS,IAAI,KAAK,gBAAgB,KAAK;AAAA,EACrD;AAAA,EAEA,WAAW,WAAmB;AAC5B,SAAK,SAAS,OAAO,SAAS;AAAA,EAChC;AAAA,EAEA,QAAQ;AACN,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA,EAEA,QAAQ;AACN,WAAO;AAAA,MACL,eAAe,KAAK,SAAS;AAAA,MAC7B,kBAAkB,KAAK;AAAA,MACvB,UAAU,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC;AAAA,IAC9C;AAAA,EACJ;AACA;AAGO,MAAM,eAAe,aAAa,YAAY;AAM9C,MAAM,kBAAkB,MAAM,CAAC,cAAmC;AACvE,SAAO,aAAa,QAAQ,SAAS;AACvC,CAAC;","names":[]}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { NextRequest } from "next/server";
|
|
2
|
-
import type { BaseUser, SessionResult } from "./types";
|
|
3
|
-
export declare function verifySession(request: NextRequest): Promise<SessionResult>;
|
|
4
|
-
/**
|
|
5
|
-
* Edge-compatible token verification using Firebase Auth REST API
|
|
6
|
-
*/
|
|
7
|
-
export declare function verifyTokenEdge(idToken: string): Promise<BaseUser | null>;
|
|
8
|
-
/**
|
|
9
|
-
* Edge-compatible session cookie verification
|
|
10
|
-
*/
|
|
11
|
-
export declare function verifySessionEdge(sessionCookie: string): Promise<BaseUser | null>;
|
|
12
|
-
/**
|
|
13
|
-
* Edge-compatible session verification using Firebase Auth REST API
|
|
14
|
-
*/
|
|
15
|
-
export declare function VerifySessionWithRestApi(request: NextRequest): Promise<SessionResult>;
|
|
16
|
-
//# sourceMappingURL=edge-session.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edge-session.d.ts","sourceRoot":"","sources":["../../../src/server/edge-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,KAAK,EAAE,QAAQ,EAAC,aAAa,EAAE,MAAM,SAAS,CAAC;AAEtD,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAgCxB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA+B1B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA+B1B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAmDxB"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
interface FirebaseTokenResult {
|
|
2
|
-
valid: boolean;
|
|
3
|
-
tenant?: string;
|
|
4
|
-
uid?: string;
|
|
5
|
-
email?: string | null;
|
|
6
|
-
emailVerified?: boolean;
|
|
7
|
-
authTime?: number;
|
|
8
|
-
issuedAt?: number;
|
|
9
|
-
expiresAt?: number;
|
|
10
|
-
error?: string;
|
|
11
|
-
}
|
|
12
|
-
export declare function verifyFirebaseToken(token: string, isSessionCookie?: boolean): Promise<FirebaseTokenResult>;
|
|
13
|
-
export {};
|
|
14
|
-
//# sourceMappingURL=jwt-edge.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jwt-edge.d.ts","sourceRoot":"","sources":["../../../src/server/jwt-edge.ts"],"names":[],"mappings":"AAsBA,UAAU,mBAAmB;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,UAAQ,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmG9G"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
interface FirebaseTokenResult {
|
|
2
|
-
valid: boolean;
|
|
3
|
-
tenant?: string;
|
|
4
|
-
uid?: string;
|
|
5
|
-
email?: string | null;
|
|
6
|
-
emailVerified?: boolean;
|
|
7
|
-
authTime?: number;
|
|
8
|
-
issuedAt?: number;
|
|
9
|
-
expiresAt?: number;
|
|
10
|
-
error?: string;
|
|
11
|
-
}
|
|
12
|
-
export declare function verifyFirebaseToken(token: string, isSessionCookie?: boolean): Promise<FirebaseTokenResult>;
|
|
13
|
-
export {};
|
|
14
|
-
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/server/jwt.ts"],"names":[],"mappings":"AAsBA,UAAU,mBAAmB;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsCD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,eAAe,UAAQ,GACtB,OAAO,CAAC,mBAAmB,CAAC,CA+F9B"}
|