@tern-secure/backend 1.2.0-canary.v20250926170202 → 1.2.0-canary.v20251002181737

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.
Files changed (52) hide show
  1. package/auth/package.json +5 -0
  2. package/dist/admin/index.d.ts +1 -1
  3. package/dist/admin/index.d.ts.map +1 -1
  4. package/dist/admin/index.js +19 -28
  5. package/dist/admin/index.js.map +1 -1
  6. package/dist/admin/index.mjs +23 -536
  7. package/dist/admin/index.mjs.map +1 -1
  8. package/dist/admin/sessionTernSecure.d.ts +3 -0
  9. package/dist/admin/sessionTernSecure.d.ts.map +1 -1
  10. package/dist/auth/getauth.d.ts +15 -0
  11. package/dist/auth/getauth.d.ts.map +1 -0
  12. package/dist/auth/index.d.ts +2 -0
  13. package/dist/auth/index.d.ts.map +1 -0
  14. package/dist/auth/index.js +694 -0
  15. package/dist/auth/index.js.map +1 -0
  16. package/dist/auth/index.mjs +53 -0
  17. package/dist/auth/index.mjs.map +1 -0
  18. package/dist/{chunk-ZMDLKXUP.mjs → chunk-4SGWLAJG.mjs} +3 -3
  19. package/dist/{chunk-ZMDLKXUP.mjs.map → chunk-4SGWLAJG.mjs.map} +1 -1
  20. package/dist/chunk-NEPV6OWI.mjs +550 -0
  21. package/dist/chunk-NEPV6OWI.mjs.map +1 -0
  22. package/dist/chunk-YKIA5EBF.mjs +142 -0
  23. package/dist/chunk-YKIA5EBF.mjs.map +1 -0
  24. package/dist/fireRestApi/emulator.d.ts +4 -0
  25. package/dist/fireRestApi/emulator.d.ts.map +1 -0
  26. package/dist/fireRestApi/endpointUrl.d.ts.map +1 -1
  27. package/dist/fireRestApi/endpoints/EmailApi.d.ts.map +1 -1
  28. package/dist/fireRestApi/endpoints/PasswordApi.d.ts.map +1 -1
  29. package/dist/fireRestApi/endpoints/SignInTokenApi.d.ts +4 -4
  30. package/dist/fireRestApi/endpoints/SignInTokenApi.d.ts.map +1 -1
  31. package/dist/fireRestApi/endpoints/SignUpApi.d.ts.map +1 -1
  32. package/dist/fireRestApi/endpoints/TokenApi.d.ts +7 -1
  33. package/dist/fireRestApi/endpoints/TokenApi.d.ts.map +1 -1
  34. package/dist/fireRestApi/request.d.ts +4 -7
  35. package/dist/fireRestApi/request.d.ts.map +1 -1
  36. package/dist/fireRestApi/resources/JSON.d.ts +6 -0
  37. package/dist/fireRestApi/resources/JSON.d.ts.map +1 -1
  38. package/dist/fireRestApi/resources/Token.d.ts +7 -1
  39. package/dist/fireRestApi/resources/Token.d.ts.map +1 -1
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +111 -31
  43. package/dist/index.js.map +1 -1
  44. package/dist/index.mjs +114 -163
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/tokens/keys.d.ts.map +1 -1
  47. package/dist/tokens/request.d.ts.map +1 -1
  48. package/dist/tokens/types.d.ts +1 -0
  49. package/dist/tokens/types.d.ts.map +1 -1
  50. package/dist/utils/options.d.ts +1 -1
  51. package/dist/utils/options.d.ts.map +1 -1
  52. package/package.json +14 -3
@@ -0,0 +1,694 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/auth/index.ts
31
+ var auth_exports = {};
32
+ __export(auth_exports, {
33
+ getAuth: () => getAuth
34
+ });
35
+ module.exports = __toCommonJS(auth_exports);
36
+
37
+ // src/admin/sessionTernSecure.ts
38
+ var import_errors = require("@tern-secure/shared/errors");
39
+
40
+ // src/constants.ts
41
+ var GOOGLE_PUBLIC_KEYS_URL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";
42
+ var MAX_CACHE_LAST_UPDATED_AT_SECONDS = 5 * 60;
43
+ var DEFAULT_CACHE_DURATION = 3600 * 1e3;
44
+ var CACHE_CONTROL_REGEX = /max-age=(\d+)/;
45
+ var Attributes = {
46
+ AuthToken: "__ternsecureAuthToken",
47
+ AuthSignature: "__ternsecureAuthSignature",
48
+ AuthStatus: "__ternsecureAuthStatus",
49
+ AuthReason: "__ternsecureAuthReason",
50
+ AuthMessage: "__ternsecureAuthMessage",
51
+ TernSecureUrl: "__ternsecureUrl"
52
+ };
53
+ var Cookies = {
54
+ Session: "__session",
55
+ CsrfToken: "__session_terncf",
56
+ IdToken: "FIREBASE_[DEFAULT]",
57
+ Refresh: "FIREBASEID_[DEFAULT]",
58
+ Custom: "__custom",
59
+ Handshake: "__ternsecure_handshake",
60
+ DevBrowser: "__ternsecure_db_jwt",
61
+ RedirectCount: "__ternsecure_redirect_count",
62
+ HandshakeNonce: "__ternsecure_handshake_nonce"
63
+ };
64
+ var Headers2 = {
65
+ Accept: "accept",
66
+ AuthMessage: "x-ternsecure-auth-message",
67
+ Authorization: "authorization",
68
+ AuthReason: "x-ternsecure-auth-reason",
69
+ AuthSignature: "x-ternsecure-auth-signature",
70
+ AuthStatus: "x-ternsecure-auth-status",
71
+ AuthToken: "x-ternsecure-auth-token",
72
+ CacheControl: "cache-control",
73
+ TernSecureRedirectTo: "x-ternsecure-redirect-to",
74
+ TernSecureRequestData: "x-ternsecure-request-data",
75
+ TernSecureUrl: "x-ternsecure-url",
76
+ CloudFrontForwardedProto: "cloudfront-forwarded-proto",
77
+ ContentType: "content-type",
78
+ ContentSecurityPolicy: "content-security-policy",
79
+ ContentSecurityPolicyReportOnly: "content-security-policy-report-only",
80
+ EnableDebug: "x-ternsecure-debug",
81
+ ForwardedHost: "x-forwarded-host",
82
+ ForwardedPort: "x-forwarded-port",
83
+ ForwardedProto: "x-forwarded-proto",
84
+ Host: "host",
85
+ Location: "location",
86
+ Nonce: "x-nonce",
87
+ Origin: "origin",
88
+ Referrer: "referer",
89
+ SecFetchDest: "sec-fetch-dest",
90
+ UserAgent: "user-agent",
91
+ ReportingEndpoints: "reporting-endpoints"
92
+ };
93
+ var ContentTypes = {
94
+ Json: "application/json"
95
+ };
96
+ var constants = {
97
+ Attributes,
98
+ Cookies,
99
+ Headers: Headers2,
100
+ ContentTypes
101
+ };
102
+
103
+ // src/utils/admin-init.ts
104
+ var import_firebase_admin = __toESM(require("firebase-admin"));
105
+
106
+ // src/utils/config.ts
107
+ var loadAdminConfig = () => ({
108
+ projectId: process.env.FIREBASE_PROJECT_ID || "",
109
+ clientEmail: process.env.FIREBASE_CLIENT_EMAIL || "",
110
+ privateKey: process.env.FIREBASE_PRIVATE_KEY || ""
111
+ });
112
+ var validateAdminConfig = (config) => {
113
+ const requiredFields = [
114
+ "projectId",
115
+ "clientEmail",
116
+ "privateKey"
117
+ ];
118
+ const errors = [];
119
+ requiredFields.forEach((field) => {
120
+ if (!config[field]) {
121
+ errors.push(`Missing required field: FIREBASE_${String(field).toUpperCase()}`);
122
+ }
123
+ });
124
+ return {
125
+ isValid: errors.length === 0,
126
+ errors,
127
+ config
128
+ };
129
+ };
130
+ var initializeAdminConfig = () => {
131
+ const config = loadAdminConfig();
132
+ const validationResult = validateAdminConfig(config);
133
+ if (!validationResult.isValid) {
134
+ throw new Error(
135
+ `Firebase Admin configuration validation failed:
136
+ ${validationResult.errors.join("\n")}`
137
+ );
138
+ }
139
+ return config;
140
+ };
141
+
142
+ // src/utils/admin-init.ts
143
+ if (!import_firebase_admin.default.apps.length) {
144
+ try {
145
+ const config = initializeAdminConfig();
146
+ import_firebase_admin.default.initializeApp({
147
+ credential: import_firebase_admin.default.credential.cert({
148
+ ...config,
149
+ privateKey: config.privateKey.replace(/\\n/g, "\n")
150
+ })
151
+ });
152
+ } catch (error) {
153
+ console.error("Firebase admin initialization error", error);
154
+ }
155
+ }
156
+ var adminTernSecureAuth = import_firebase_admin.default.auth();
157
+ var adminTernSecureDb = import_firebase_admin.default.firestore();
158
+ var TernSecureTenantManager = import_firebase_admin.default.auth().tenantManager();
159
+ function getAuthForTenant(tenantId) {
160
+ if (tenantId) {
161
+ return TernSecureTenantManager.authForTenant(tenantId);
162
+ }
163
+ return import_firebase_admin.default.auth();
164
+ }
165
+
166
+ // src/admin/sessionTernSecure.ts
167
+ var SESSION_CONSTANTS = {
168
+ COOKIE_NAME: "_session_cookie",
169
+ //DEFAULT_EXPIRES_IN_MS: 60 * 60 * 24 * 5 * 1000, // 5 days
170
+ //DEFAULT_EXPIRES_IN_SECONDS: 60 * 60 * 24 * 5, // 5days
171
+ DEFAULT_EXPIRES_IN_MS: 5 * 60 * 1e3,
172
+ // 5 minutes
173
+ DEFAULT_EXPIRES_IN_SECONDS: 5 * 60,
174
+ REVOKE_REFRESH_TOKENS_ON_SIGNOUT: true
175
+ };
176
+ var COOKIE_OPTIONS = {
177
+ httpOnly: true,
178
+ secure: process.env.NODE_ENV === "production",
179
+ sameSite: "strict",
180
+ path: "/"
181
+ };
182
+ var DEFAULT_COOKIE_CONFIG = {
183
+ DEFAULT_EXPIRES_IN_MS: 5 * 60 * 1e3,
184
+ // 5 minutes
185
+ DEFAULT_EXPIRES_IN_SECONDS: 5 * 60,
186
+ REVOKE_REFRESH_TOKENS_ON_SIGNOUT: true
187
+ };
188
+ var DEFAULT_COOKIE_OPTIONS = {
189
+ httpOnly: true,
190
+ secure: process.env.NODE_ENV === "production",
191
+ sameSite: "strict",
192
+ path: "/"
193
+ };
194
+ async function createCustomTokenClaims(uid, developerClaims) {
195
+ const adminAuth = getAuthForTenant();
196
+ try {
197
+ const customToken = await adminAuth.createCustomToken(uid, developerClaims);
198
+ return customToken;
199
+ } catch (error) {
200
+ console.error("[createCustomToken] Error creating custom token:", error);
201
+ return "";
202
+ }
203
+ }
204
+
205
+ // src/admin/nextSessionTernSecure.ts
206
+ var import_errors2 = require("@tern-secure/shared/errors");
207
+ var import_headers = require("next/headers");
208
+ var SESSION_CONSTANTS2 = {
209
+ COOKIE_NAME: constants.Cookies.Session,
210
+ DEFAULT_EXPIRES_IN_MS: 60 * 60 * 24 * 5 * 1e3,
211
+ // 5 days
212
+ DEFAULT_EXPIRES_IN_SECONDS: 60 * 60 * 24 * 5,
213
+ REVOKE_REFRESH_TOKENS_ON_SIGNOUT: true
214
+ };
215
+
216
+ // src/tokens/ternSecureRequest.ts
217
+ var import_cookie = require("cookie");
218
+
219
+ // src/jwt/verifyJwt.ts
220
+ var import_jose2 = require("jose");
221
+
222
+ // src/utils/errors.ts
223
+ var TokenVerificationErrorReason = {
224
+ TokenExpired: "token-expired",
225
+ TokenInvalid: "token-invalid",
226
+ TokenInvalidAlgorithm: "token-invalid-algorithm",
227
+ TokenInvalidAuthorizedParties: "token-invalid-authorized-parties",
228
+ TokenInvalidSignature: "token-invalid-signature",
229
+ TokenNotActiveYet: "token-not-active-yet",
230
+ TokenIatInTheFuture: "token-iat-in-the-future",
231
+ TokenVerificationFailed: "token-verification-failed",
232
+ InvalidSecretKey: "secret-key-invalid",
233
+ LocalJWKMissing: "jwk-local-missing",
234
+ RemoteJWKFailedToLoad: "jwk-remote-failed-to-load",
235
+ RemoteJWKInvalid: "jwk-remote-invalid",
236
+ RemoteJWKMissing: "jwk-remote-missing",
237
+ JWKFailedToResolve: "jwk-failed-to-resolve",
238
+ JWKKidMismatch: "jwk-kid-mismatch"
239
+ };
240
+ var TokenVerificationError = class _TokenVerificationError extends Error {
241
+ reason;
242
+ tokenCarrier;
243
+ constructor({
244
+ message,
245
+ reason
246
+ }) {
247
+ super(message);
248
+ Object.setPrototypeOf(this, _TokenVerificationError.prototype);
249
+ this.reason = reason;
250
+ this.message = message;
251
+ }
252
+ getFullMessage() {
253
+ return `${[this.message].filter((m) => m).join(" ")} (reason=${this.reason}, token-carrier=${this.tokenCarrier})`;
254
+ }
255
+ };
256
+
257
+ // src/utils/mapDecode.ts
258
+ function mapJwtPayloadToDecodedIdToken(payload) {
259
+ const decodedIdToken = payload;
260
+ decodedIdToken.uid = decodedIdToken.sub;
261
+ return decodedIdToken;
262
+ }
263
+
264
+ // src/utils/rfc4648.ts
265
+ var base64url = {
266
+ parse(string, opts) {
267
+ return parse2(string, base64UrlEncoding, opts);
268
+ },
269
+ stringify(data, opts) {
270
+ return stringify(data, base64UrlEncoding, opts);
271
+ }
272
+ };
273
+ var base64UrlEncoding = {
274
+ chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
275
+ bits: 6
276
+ };
277
+ function parse2(string, encoding, opts = {}) {
278
+ if (!encoding.codes) {
279
+ encoding.codes = {};
280
+ for (let i = 0; i < encoding.chars.length; ++i) {
281
+ encoding.codes[encoding.chars[i]] = i;
282
+ }
283
+ }
284
+ if (!opts.loose && string.length * encoding.bits & 7) {
285
+ throw new SyntaxError("Invalid padding");
286
+ }
287
+ let end = string.length;
288
+ while (string[end - 1] === "=") {
289
+ --end;
290
+ if (!opts.loose && !((string.length - end) * encoding.bits & 7)) {
291
+ throw new SyntaxError("Invalid padding");
292
+ }
293
+ }
294
+ const out = new (opts.out ?? Uint8Array)(end * encoding.bits / 8 | 0);
295
+ let bits = 0;
296
+ let buffer = 0;
297
+ let written = 0;
298
+ for (let i = 0; i < end; ++i) {
299
+ const value = encoding.codes[string[i]];
300
+ if (value === void 0) {
301
+ throw new SyntaxError("Invalid character " + string[i]);
302
+ }
303
+ buffer = buffer << encoding.bits | value;
304
+ bits += encoding.bits;
305
+ if (bits >= 8) {
306
+ bits -= 8;
307
+ out[written++] = 255 & buffer >> bits;
308
+ }
309
+ }
310
+ if (bits >= encoding.bits || 255 & buffer << 8 - bits) {
311
+ throw new SyntaxError("Unexpected end of data");
312
+ }
313
+ return out;
314
+ }
315
+ function stringify(data, encoding, opts = {}) {
316
+ const { pad = true } = opts;
317
+ const mask = (1 << encoding.bits) - 1;
318
+ let out = "";
319
+ let bits = 0;
320
+ let buffer = 0;
321
+ for (let i = 0; i < data.length; ++i) {
322
+ buffer = buffer << 8 | 255 & data[i];
323
+ bits += 8;
324
+ while (bits > encoding.bits) {
325
+ bits -= encoding.bits;
326
+ out += encoding.chars[mask & buffer >> bits];
327
+ }
328
+ }
329
+ if (bits) {
330
+ out += encoding.chars[mask & buffer << encoding.bits - bits];
331
+ }
332
+ if (pad) {
333
+ while (out.length * encoding.bits & 7) {
334
+ out += "=";
335
+ }
336
+ }
337
+ return out;
338
+ }
339
+
340
+ // src/jwt/cryptoKeys.ts
341
+ var import_jose = require("jose");
342
+ async function importKey(key, algorithm) {
343
+ if (typeof key === "object") {
344
+ const result = await (0, import_jose.importJWK)(key, algorithm);
345
+ if (result instanceof Uint8Array) {
346
+ throw new Error("Unexpected Uint8Array result from JWK import");
347
+ }
348
+ return result;
349
+ }
350
+ const keyString = key.trim();
351
+ if (keyString.includes("-----BEGIN CERTIFICATE-----")) {
352
+ return await (0, import_jose.importX509)(keyString, algorithm);
353
+ }
354
+ if (keyString.includes("-----BEGIN PUBLIC KEY-----")) {
355
+ return await (0, import_jose.importSPKI)(keyString, algorithm);
356
+ }
357
+ try {
358
+ return await (0, import_jose.importSPKI)(keyString, algorithm);
359
+ } catch (error) {
360
+ throw new Error(
361
+ `Unsupported key format. Supported formats: X.509 certificate (PEM), SPKI (PEM), JWK (JSON object or string). Error: ${error}`
362
+ );
363
+ }
364
+ }
365
+
366
+ // src/jwt/algorithms.ts
367
+ var algToHash = {
368
+ RS256: "SHA-256",
369
+ RS384: "SHA-384",
370
+ RS512: "SHA-512"
371
+ };
372
+ var algs = Object.keys(algToHash);
373
+
374
+ // src/jwt/verifyContent.ts
375
+ var verifyHeaderKid = (kid) => {
376
+ if (typeof kid === "undefined") {
377
+ return;
378
+ }
379
+ if (typeof kid !== "string") {
380
+ throw new TokenVerificationError({
381
+ reason: TokenVerificationErrorReason.TokenInvalid,
382
+ message: `Invalid JWT kid ${JSON.stringify(kid)}. Expected a string.`
383
+ });
384
+ }
385
+ };
386
+ var verifySubClaim = (sub) => {
387
+ if (typeof sub !== "string") {
388
+ throw new TokenVerificationError({
389
+ reason: TokenVerificationErrorReason.TokenVerificationFailed,
390
+ message: `Subject claim (sub) is required and must be a string. Received ${JSON.stringify(sub)}.`
391
+ });
392
+ }
393
+ };
394
+ var verifyExpirationClaim = (exp, clockSkewInMs) => {
395
+ if (typeof exp !== "number") {
396
+ throw new TokenVerificationError({
397
+ reason: TokenVerificationErrorReason.TokenVerificationFailed,
398
+ message: `Invalid JWT expiry date (exp) claim ${JSON.stringify(exp)}. Expected a number.`
399
+ });
400
+ }
401
+ const currentDate = new Date(Date.now());
402
+ const expiryDate = /* @__PURE__ */ new Date(0);
403
+ expiryDate.setUTCSeconds(exp);
404
+ const expired = expiryDate.getTime() <= currentDate.getTime() - clockSkewInMs;
405
+ if (expired) {
406
+ throw new TokenVerificationError({
407
+ reason: TokenVerificationErrorReason.TokenExpired,
408
+ message: `JWT is expired. Expiry date: ${expiryDate.toUTCString()}, Current date: ${currentDate.toUTCString()}.`
409
+ });
410
+ }
411
+ };
412
+ var verifyIssuedAtClaim = (iat, clockSkewInMs) => {
413
+ if (typeof iat === "undefined") {
414
+ return;
415
+ }
416
+ if (typeof iat !== "number") {
417
+ throw new TokenVerificationError({
418
+ reason: TokenVerificationErrorReason.TokenVerificationFailed,
419
+ message: `Invalid JWT issued at date claim (iat) ${JSON.stringify(iat)}. Expected a number.`
420
+ });
421
+ }
422
+ const currentDate = new Date(Date.now());
423
+ const issuedAtDate = /* @__PURE__ */ new Date(0);
424
+ issuedAtDate.setUTCSeconds(iat);
425
+ const postIssued = issuedAtDate.getTime() > currentDate.getTime() + clockSkewInMs;
426
+ if (postIssued) {
427
+ throw new TokenVerificationError({
428
+ reason: TokenVerificationErrorReason.TokenIatInTheFuture,
429
+ message: `JWT issued at date claim (iat) is in the future. Issued at date: ${issuedAtDate.toUTCString()}; Current date: ${currentDate.toUTCString()};`
430
+ });
431
+ }
432
+ };
433
+
434
+ // src/jwt/verifyJwt.ts
435
+ var DEFAULT_CLOCK_SKEW_IN_MS = 5 * 1e3;
436
+ async function verifySignature(jwt, key) {
437
+ const { header, raw } = jwt;
438
+ const joseAlgorithm = header.alg || "RS256";
439
+ try {
440
+ const publicKey = await importKey(key, joseAlgorithm);
441
+ const { payload } = await (0, import_jose2.jwtVerify)(raw.text, publicKey);
442
+ return { data: payload };
443
+ } catch (error) {
444
+ return {
445
+ errors: [
446
+ new TokenVerificationError({
447
+ reason: TokenVerificationErrorReason.TokenInvalidSignature,
448
+ message: error.message
449
+ })
450
+ ]
451
+ };
452
+ }
453
+ }
454
+ function ternDecodeJwt(token) {
455
+ try {
456
+ const header = (0, import_jose2.decodeProtectedHeader)(token);
457
+ const payload = (0, import_jose2.decodeJwt)(token);
458
+ const tokenParts = (token || "").toString().split(".");
459
+ if (tokenParts.length !== 3) {
460
+ return {
461
+ errors: [
462
+ new TokenVerificationError({
463
+ reason: TokenVerificationErrorReason.TokenInvalid,
464
+ message: "Invalid JWT format"
465
+ })
466
+ ]
467
+ };
468
+ }
469
+ const [rawHeader, rawPayload, rawSignature] = tokenParts;
470
+ const signature = base64url.parse(rawSignature, { loose: true });
471
+ const data = {
472
+ header,
473
+ payload,
474
+ signature,
475
+ raw: {
476
+ header: rawHeader,
477
+ payload: rawPayload,
478
+ signature: rawSignature,
479
+ text: token
480
+ }
481
+ };
482
+ return { data };
483
+ } catch (error) {
484
+ return {
485
+ errors: [
486
+ new TokenVerificationError({
487
+ reason: TokenVerificationErrorReason.TokenInvalid,
488
+ message: error.message
489
+ })
490
+ ]
491
+ };
492
+ }
493
+ }
494
+ async function verifyJwt(token, options) {
495
+ const { key } = options;
496
+ const clockSkew = options.clockSkewInMs || DEFAULT_CLOCK_SKEW_IN_MS;
497
+ const { data: decoded, errors } = ternDecodeJwt(token);
498
+ if (errors) {
499
+ return { errors };
500
+ }
501
+ const { header, payload } = decoded;
502
+ try {
503
+ verifyHeaderKid(header.kid);
504
+ verifySubClaim(payload.sub);
505
+ verifyExpirationClaim(payload.exp, clockSkew);
506
+ verifyIssuedAtClaim(payload.iat, clockSkew);
507
+ } catch (error) {
508
+ return { errors: [error] };
509
+ }
510
+ const { data: verifiedPayload, errors: signatureErrors } = await verifySignature(decoded, key);
511
+ if (signatureErrors) {
512
+ return {
513
+ errors: [
514
+ new TokenVerificationError({
515
+ reason: TokenVerificationErrorReason.TokenInvalidSignature,
516
+ message: "Token signature verification failed."
517
+ })
518
+ ]
519
+ };
520
+ }
521
+ const decodedIdToken = mapJwtPayloadToDecodedIdToken(verifiedPayload);
522
+ return { data: decodedIdToken };
523
+ }
524
+
525
+ // src/tokens/keys.ts
526
+ var cache = {};
527
+ var lastUpdatedAt = 0;
528
+ var googleExpiresAt = 0;
529
+ function getFromCache(kid) {
530
+ return cache[kid];
531
+ }
532
+ function getCacheValues() {
533
+ return Object.values(cache);
534
+ }
535
+ function setInCache(kid, certificate, shouldExpire = true) {
536
+ cache[kid] = certificate;
537
+ lastUpdatedAt = shouldExpire ? Date.now() : -1;
538
+ }
539
+ async function fetchPublicKeys(keyUrl) {
540
+ const url = new URL(keyUrl);
541
+ const response = await fetch(url);
542
+ if (!response.ok) {
543
+ throw new TokenVerificationError({
544
+ message: `Error loading public keys from ${url.href} with code=${response.status} `,
545
+ reason: TokenVerificationErrorReason.TokenInvalid
546
+ });
547
+ }
548
+ const data = await response.json();
549
+ const expiresAt = getExpiresAt(response);
550
+ return {
551
+ keys: data,
552
+ expiresAt
553
+ };
554
+ }
555
+ async function loadJWKFromRemote({
556
+ keyURL = GOOGLE_PUBLIC_KEYS_URL,
557
+ skipJwksCache,
558
+ kid
559
+ }) {
560
+ if (skipJwksCache || isCacheExpired() || !getFromCache(kid)) {
561
+ const { keys, expiresAt } = await fetchPublicKeys(keyURL);
562
+ if (!keys || Object.keys(keys).length === 0) {
563
+ throw new TokenVerificationError({
564
+ message: `The JWKS endpoint ${keyURL} returned no keys`,
565
+ reason: TokenVerificationErrorReason.RemoteJWKFailedToLoad
566
+ });
567
+ }
568
+ googleExpiresAt = expiresAt;
569
+ Object.entries(keys).forEach(([keyId, cert2]) => {
570
+ setInCache(keyId, cert2);
571
+ });
572
+ }
573
+ const cert = getFromCache(kid);
574
+ if (!cert) {
575
+ getCacheValues();
576
+ const availableKids = Object.keys(cache).sort().join(", ");
577
+ throw new TokenVerificationError({
578
+ message: `No public key found for kid "${kid}". Available kids: [${availableKids}]`,
579
+ reason: TokenVerificationErrorReason.TokenInvalid
580
+ });
581
+ }
582
+ return cert;
583
+ }
584
+ function isCacheExpired() {
585
+ const now = Date.now();
586
+ if (lastUpdatedAt === -1) {
587
+ return false;
588
+ }
589
+ const cacheAge = now - lastUpdatedAt;
590
+ const maxCacheAge = MAX_CACHE_LAST_UPDATED_AT_SECONDS * 1e3;
591
+ const localCacheExpired = cacheAge >= maxCacheAge;
592
+ const googleCacheExpired = now >= googleExpiresAt;
593
+ const isExpired = localCacheExpired || googleCacheExpired;
594
+ if (isExpired) {
595
+ cache = {};
596
+ }
597
+ return isExpired;
598
+ }
599
+ function getExpiresAt(res) {
600
+ const cacheControlHeader = res.headers.get("cache-control");
601
+ if (!cacheControlHeader) {
602
+ return Date.now() + DEFAULT_CACHE_DURATION;
603
+ }
604
+ const maxAgeMatch = cacheControlHeader.match(CACHE_CONTROL_REGEX);
605
+ const maxAge = maxAgeMatch ? parseInt(maxAgeMatch[1], 10) : DEFAULT_CACHE_DURATION / 1e3;
606
+ return Date.now() + maxAge * 1e3;
607
+ }
608
+
609
+ // src/tokens/verify.ts
610
+ async function verifyToken(token, options) {
611
+ const { data: decodedResult, errors } = ternDecodeJwt(token);
612
+ if (errors) {
613
+ return { errors };
614
+ }
615
+ const { header } = decodedResult;
616
+ const { kid } = header;
617
+ if (!kid) {
618
+ return {
619
+ errors: [
620
+ new TokenVerificationError({
621
+ reason: TokenVerificationErrorReason.TokenInvalid,
622
+ message: 'JWT "kid" header is missing.'
623
+ })
624
+ ]
625
+ };
626
+ }
627
+ try {
628
+ const key = options.jwtKey || await loadJWKFromRemote({ ...options, kid });
629
+ if (!key) {
630
+ return {
631
+ errors: [
632
+ new TokenVerificationError({
633
+ reason: TokenVerificationErrorReason.TokenInvalid,
634
+ message: `No public key found for kid "${kid}".`
635
+ })
636
+ ]
637
+ };
638
+ }
639
+ return await verifyJwt(token, { ...options, key });
640
+ } catch (error) {
641
+ if (error instanceof TokenVerificationError) {
642
+ return { errors: [error] };
643
+ }
644
+ return {
645
+ errors: [error]
646
+ };
647
+ }
648
+ }
649
+
650
+ // src/auth/getauth.ts
651
+ function getAuth(options) {
652
+ const { apiKey, tenantId } = options.firebaseConfig || {};
653
+ async function customForIdAndRefreshToken(customToken) {
654
+ if (!apiKey) {
655
+ throw new Error("API Key is required to create custom token");
656
+ }
657
+ const response = await options.apiClient?.tokens.exchangeCustomForIdAndRefreshTokens(apiKey, {
658
+ token: customToken,
659
+ returnSecureToken: true
660
+ });
661
+ return {
662
+ idToken: response?.idToken || "",
663
+ refreshToken: response?.refreshToken || ""
664
+ };
665
+ }
666
+ async function createCustomIdAndRefreshToken(idToken) {
667
+ const decoded = await verifyToken(idToken, options);
668
+ const { data, errors } = decoded;
669
+ if (errors) {
670
+ console.error("Token Verification failed:", errors);
671
+ throw errors[0];
672
+ }
673
+ const customToken = await createCustomTokenClaims(data.uid, {
674
+ emailVerified: data.email_verified,
675
+ source_sign_in_provider: data.firebase.sign_in_provider
676
+ });
677
+ const idAndRefreshTokens = await customForIdAndRefreshToken(
678
+ customToken
679
+ );
680
+ return {
681
+ ...idAndRefreshTokens,
682
+ customToken
683
+ };
684
+ }
685
+ return {
686
+ customForIdAndRefreshToken,
687
+ createCustomIdAndRefreshToken
688
+ };
689
+ }
690
+ // Annotate the CommonJS export names for ESM import in node:
691
+ 0 && (module.exports = {
692
+ getAuth
693
+ });
694
+ //# sourceMappingURL=index.js.map