@tern-secure/backend 1.2.0-canary.v20251003171521 → 1.2.0-canary.v20251008131428

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 (49) hide show
  1. package/dist/admin/index.mjs +531 -22
  2. package/dist/admin/index.mjs.map +1 -1
  3. package/dist/auth/getauth.d.ts +8 -0
  4. package/dist/auth/getauth.d.ts.map +1 -1
  5. package/dist/auth/index.js +136 -200
  6. package/dist/auth/index.js.map +1 -1
  7. package/dist/auth/index.mjs +4 -67
  8. package/dist/auth/index.mjs.map +1 -1
  9. package/dist/{chunk-4SGWLAJG.mjs → chunk-3ZLDOHI2.mjs} +4 -68
  10. package/dist/chunk-3ZLDOHI2.mjs.map +1 -0
  11. package/dist/{chunk-WZYVAHZ3.mjs → chunk-SVZUAXAW.mjs} +115 -1
  12. package/dist/chunk-SVZUAXAW.mjs.map +1 -0
  13. package/dist/chunk-VSYYHCUV.mjs +71 -0
  14. package/dist/chunk-VSYYHCUV.mjs.map +1 -0
  15. package/dist/{chunk-YKIA5EBF.mjs → chunk-YGNTGJTP.mjs} +94 -4
  16. package/dist/chunk-YGNTGJTP.mjs.map +1 -0
  17. package/dist/fireRestApi/endpoints/TokenApi.d.ts +2 -2
  18. package/dist/fireRestApi/endpoints/TokenApi.d.ts.map +1 -1
  19. package/dist/index.d.ts +12 -12
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +359 -92
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +84 -7
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/jwt/customJwt.d.ts +11 -0
  26. package/dist/jwt/customJwt.d.ts.map +1 -0
  27. package/dist/jwt/index.d.ts +1 -0
  28. package/dist/jwt/index.d.ts.map +1 -1
  29. package/dist/jwt/index.js +104 -0
  30. package/dist/jwt/index.js.map +1 -1
  31. package/dist/jwt/index.mjs +7 -1
  32. package/dist/jwt/index.mjs.map +1 -1
  33. package/dist/tokens/cookie.d.ts +5 -0
  34. package/dist/tokens/cookie.d.ts.map +1 -0
  35. package/dist/tokens/request.d.ts.map +1 -1
  36. package/dist/tokens/types.d.ts +1 -12
  37. package/dist/tokens/types.d.ts.map +1 -1
  38. package/dist/utils/errors.d.ts +12 -0
  39. package/dist/utils/errors.d.ts.map +1 -1
  40. package/dist/utils/options.d.ts +3 -3
  41. package/dist/utils/options.d.ts.map +1 -1
  42. package/package.json +3 -3
  43. package/dist/chunk-4SGWLAJG.mjs.map +0 -1
  44. package/dist/chunk-WZYVAHZ3.mjs.map +0 -1
  45. package/dist/chunk-XTYEXHJD.mjs +0 -554
  46. package/dist/chunk-XTYEXHJD.mjs.map +0 -1
  47. package/dist/chunk-YKIA5EBF.mjs.map +0 -1
  48. package/dist/tokens/sessionConfig.d.ts +0 -14
  49. package/dist/tokens/sessionConfig.d.ts.map +0 -1
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
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
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/auth/index.ts
@@ -34,191 +24,103 @@ __export(auth_exports, {
34
24
  });
35
25
  module.exports = __toCommonJS(auth_exports);
36
26
 
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
- );
27
+ // src/jwt/customJwt.ts
28
+ var import_jose = require("jose");
29
+ var CustomTokenError = class extends Error {
30
+ constructor(message, code) {
31
+ super(message);
32
+ this.code = code;
33
+ this.name = "CustomTokenError";
138
34
  }
139
- return config;
140
35
  };
141
-
142
- // src/utils/admin-init.ts
143
- if (!import_firebase_admin.default.apps.length) {
36
+ var RESERVED_CLAIMS = [
37
+ "acr",
38
+ "amr",
39
+ "at_hash",
40
+ "aud",
41
+ "auth_time",
42
+ "azp",
43
+ "cnf",
44
+ "c_hash",
45
+ "exp",
46
+ "firebase",
47
+ "iat",
48
+ "iss",
49
+ "jti",
50
+ "nbf",
51
+ "nonce",
52
+ "sub"
53
+ ];
54
+ async function createCustomTokenJwt(uid, developerClaims) {
144
55
  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
- });
56
+ const privateKey = process.env.FIREBASE_PRIVATE_KEY;
57
+ const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;
58
+ if (!privateKey || !clientEmail) {
59
+ return {
60
+ errors: [
61
+ new CustomTokenError(
62
+ "Missing FIREBASE_PRIVATE_KEY or FIREBASE_CLIENT_EMAIL environment variables",
63
+ "MISSING_ENV_VARS"
64
+ )
65
+ ]
66
+ };
67
+ }
68
+ if (!uid || typeof uid !== "string") {
69
+ return {
70
+ errors: [new CustomTokenError("uid must be a non-empty string", "INVALID_UID")]
71
+ };
72
+ }
73
+ if (uid.length > 128) {
74
+ return {
75
+ errors: [new CustomTokenError("uid must not exceed 128 characters", "UID_TOO_LONG")]
76
+ };
77
+ }
78
+ if (developerClaims) {
79
+ for (const claim of Object.keys(developerClaims)) {
80
+ if (RESERVED_CLAIMS.includes(claim)) {
81
+ return {
82
+ errors: [new CustomTokenError(`Custom claim '${claim}' is reserved`, "RESERVED_CLAIM")]
83
+ };
84
+ }
85
+ }
86
+ }
87
+ const expiresIn = 3600;
88
+ const now = Math.floor(Date.now() / 1e3);
89
+ const parsedPrivateKey = await (0, import_jose.importPKCS8)(privateKey.replace(/\\n/g, "\n"), "RS256");
90
+ const payload = {
91
+ iss: clientEmail,
92
+ sub: clientEmail,
93
+ aud: "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
94
+ iat: now,
95
+ exp: now + expiresIn,
96
+ uid,
97
+ ...developerClaims
98
+ };
99
+ const jwt = await new import_jose.SignJWT(payload).setProtectedHeader({ alg: "RS256", typ: "JWT" }).setIssuedAt(now).setExpirationTime(now + expiresIn).setIssuer(clientEmail).setSubject(clientEmail).setAudience(
100
+ "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
101
+ ).sign(parsedPrivateKey);
102
+ return {
103
+ data: jwt
104
+ };
152
105
  } catch (error) {
153
- console.error("Firebase admin initialization error", error);
106
+ const message = error instanceof Error ? error.message : "Unknown error occurred";
107
+ return {
108
+ errors: [
109
+ new CustomTokenError(`Failed to create custom token: ${message}`, "TOKEN_CREATION_FAILED")
110
+ ]
111
+ };
154
112
  }
155
113
  }
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 "";
114
+ async function createCustomToken(uid, developerClaims) {
115
+ const { data, errors } = await createCustomTokenJwt(uid, developerClaims);
116
+ if (errors) {
117
+ throw errors[0];
202
118
  }
119
+ return data;
203
120
  }
204
121
 
205
- // src/admin/nextSessionTernSecure.ts
206
- var import_cookie = require("@tern-secure/shared/cookie");
207
- var import_errors2 = require("@tern-secure/shared/errors");
208
- var import_headers = require("next/headers");
209
- var SESSION_CONSTANTS2 = {
210
- COOKIE_NAME: constants.Cookies.Session,
211
- DEFAULT_EXPIRES_IN_MS: 60 * 60 * 24 * 5 * 1e3,
212
- // 5 days
213
- DEFAULT_EXPIRES_IN_SECONDS: 60 * 60 * 24 * 5,
214
- REVOKE_REFRESH_TOKENS_ON_SIGNOUT: true
215
- };
216
-
217
- // src/tokens/ternSecureRequest.ts
218
- var import_cookie2 = require("cookie");
219
-
220
122
  // src/jwt/verifyJwt.ts
221
- var import_jose2 = require("jose");
123
+ var import_jose3 = require("jose");
222
124
 
223
125
  // src/utils/errors.ts
224
126
  var TokenVerificationErrorReason = {
@@ -265,7 +167,7 @@ function mapJwtPayloadToDecodedIdToken(payload) {
265
167
  // src/utils/rfc4648.ts
266
168
  var base64url = {
267
169
  parse(string, opts) {
268
- return parse2(string, base64UrlEncoding, opts);
170
+ return parse(string, base64UrlEncoding, opts);
269
171
  },
270
172
  stringify(data, opts) {
271
173
  return stringify(data, base64UrlEncoding, opts);
@@ -275,7 +177,7 @@ var base64UrlEncoding = {
275
177
  chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
276
178
  bits: 6
277
179
  };
278
- function parse2(string, encoding, opts = {}) {
180
+ function parse(string, encoding, opts = {}) {
279
181
  if (!encoding.codes) {
280
182
  encoding.codes = {};
281
183
  for (let i = 0; i < encoding.chars.length; ++i) {
@@ -339,10 +241,10 @@ function stringify(data, encoding, opts = {}) {
339
241
  }
340
242
 
341
243
  // src/jwt/cryptoKeys.ts
342
- var import_jose = require("jose");
244
+ var import_jose2 = require("jose");
343
245
  async function importKey(key, algorithm) {
344
246
  if (typeof key === "object") {
345
- const result = await (0, import_jose.importJWK)(key, algorithm);
247
+ const result = await (0, import_jose2.importJWK)(key, algorithm);
346
248
  if (result instanceof Uint8Array) {
347
249
  throw new Error("Unexpected Uint8Array result from JWK import");
348
250
  }
@@ -350,13 +252,13 @@ async function importKey(key, algorithm) {
350
252
  }
351
253
  const keyString = key.trim();
352
254
  if (keyString.includes("-----BEGIN CERTIFICATE-----")) {
353
- return await (0, import_jose.importX509)(keyString, algorithm);
255
+ return await (0, import_jose2.importX509)(keyString, algorithm);
354
256
  }
355
257
  if (keyString.includes("-----BEGIN PUBLIC KEY-----")) {
356
- return await (0, import_jose.importSPKI)(keyString, algorithm);
258
+ return await (0, import_jose2.importSPKI)(keyString, algorithm);
357
259
  }
358
260
  try {
359
- return await (0, import_jose.importSPKI)(keyString, algorithm);
261
+ return await (0, import_jose2.importSPKI)(keyString, algorithm);
360
262
  } catch (error) {
361
263
  throw new Error(
362
264
  `Unsupported key format. Supported formats: X.509 certificate (PEM), SPKI (PEM), JWK (JSON object or string). Error: ${error}`
@@ -439,7 +341,7 @@ async function verifySignature(jwt, key) {
439
341
  const joseAlgorithm = header.alg || "RS256";
440
342
  try {
441
343
  const publicKey = await importKey(key, joseAlgorithm);
442
- const { payload } = await (0, import_jose2.jwtVerify)(raw.text, publicKey);
344
+ const { payload } = await (0, import_jose3.jwtVerify)(raw.text, publicKey);
443
345
  return { data: payload };
444
346
  } catch (error) {
445
347
  return {
@@ -454,8 +356,8 @@ async function verifySignature(jwt, key) {
454
356
  }
455
357
  function ternDecodeJwt(token) {
456
358
  try {
457
- const header = (0, import_jose2.decodeProtectedHeader)(token);
458
- const payload = (0, import_jose2.decodeJwt)(token);
359
+ const header = (0, import_jose3.decodeProtectedHeader)(token);
360
+ const payload = (0, import_jose3.decodeJwt)(token);
459
361
  const tokenParts = (token || "").toString().split(".");
460
362
  if (tokenParts.length !== 3) {
461
363
  return {
@@ -523,6 +425,12 @@ async function verifyJwt(token, options) {
523
425
  return { data: decodedIdToken };
524
426
  }
525
427
 
428
+ // src/constants.ts
429
+ var GOOGLE_PUBLIC_KEYS_URL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";
430
+ var MAX_CACHE_LAST_UPDATED_AT_SECONDS = 5 * 60;
431
+ var DEFAULT_CACHE_DURATION = 3600 * 1e3;
432
+ var CACHE_CONTROL_REGEX = /max-age=(\d+)/;
433
+
526
434
  // src/tokens/keys.ts
527
435
  var cache = {};
528
436
  var lastUpdatedAt = 0;
@@ -649,6 +557,8 @@ async function verifyToken(token, options) {
649
557
  }
650
558
 
651
559
  // src/auth/getauth.ts
560
+ var API_KEY_ERROR = "API Key is required";
561
+ var NO_DATA_ERROR = "No token data received";
652
562
  function parseFirebaseResponse(data) {
653
563
  if (typeof data === "string") {
654
564
  try {
@@ -660,13 +570,38 @@ function parseFirebaseResponse(data) {
660
570
  return data;
661
571
  }
662
572
  function getAuth(options) {
663
- const { apiKey } = options.firebaseConfig || {};
573
+ const { apiKey } = options;
574
+ const firebaseApiKey = options.firebaseConfig?.apiKey;
575
+ const effectiveApiKey = apiKey || firebaseApiKey;
576
+ async function refreshExpiredIdToken(refreshToken, opts) {
577
+ if (!effectiveApiKey) {
578
+ return { data: null, error: new Error(API_KEY_ERROR) };
579
+ }
580
+ const response = await options.apiClient?.tokens.refreshToken(effectiveApiKey, {
581
+ refresh_token: refreshToken,
582
+ request_origin: opts.referer
583
+ });
584
+ if (!response?.data) {
585
+ return {
586
+ data: null,
587
+ error: new Error(NO_DATA_ERROR)
588
+ };
589
+ }
590
+ const parsedData = parseFirebaseResponse(response.data);
591
+ return {
592
+ data: {
593
+ idToken: parsedData.id_token,
594
+ refreshToken: parsedData.refresh_token
595
+ },
596
+ error: null
597
+ };
598
+ }
664
599
  async function customForIdAndRefreshToken(customToken, opts) {
665
- if (!apiKey) {
600
+ if (!effectiveApiKey) {
666
601
  throw new Error("API Key is required to create custom token");
667
602
  }
668
603
  const response = await options.apiClient?.tokens.exchangeCustomForIdAndRefreshTokens(
669
- apiKey,
604
+ effectiveApiKey,
670
605
  {
671
606
  token: customToken,
672
607
  returnSecureToken: true
@@ -690,7 +625,7 @@ function getAuth(options) {
690
625
  if (errors) {
691
626
  throw errors[0];
692
627
  }
693
- const customToken = await createCustomTokenClaims(data.uid, {
628
+ const customToken = await createCustomToken(data.uid, {
694
629
  emailVerified: data.email_verified,
695
630
  source_sign_in_provider: data.firebase.sign_in_provider
696
631
  });
@@ -704,7 +639,8 @@ function getAuth(options) {
704
639
  }
705
640
  return {
706
641
  customForIdAndRefreshToken,
707
- createCustomIdAndRefreshToken
642
+ createCustomIdAndRefreshToken,
643
+ refreshExpiredIdToken
708
644
  };
709
645
  }
710
646
  // Annotate the CommonJS export names for ESM import in node: