@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
package/dist/index.mjs CHANGED
@@ -1,17 +1,13 @@
1
1
  import {
2
- CACHE_CONTROL_REGEX,
3
- DEFAULT_CACHE_DURATION,
4
- MAX_CACHE_LAST_UPDATED_AT_SECONDS,
5
- SESSION_COOKIE_PUBLIC_KEYS_URL,
2
+ verifyToken
3
+ } from "./chunk-YKIA5EBF.mjs";
4
+ import {
6
5
  constants,
7
6
  createTernSecureRequest
8
- } from "./chunk-ZMDLKXUP.mjs";
7
+ } from "./chunk-4SGWLAJG.mjs";
9
8
  import {
10
9
  TokenVerificationError,
11
- TokenVerificationErrorReason,
12
- mapJwtPayloadToDecodedIdToken,
13
- ternDecodeJwt,
14
- verifyJwt
10
+ mapJwtPayloadToDecodedIdToken
15
11
  } from "./chunk-WZYVAHZ3.mjs";
16
12
 
17
13
  // src/tokens/authstate.ts
@@ -126,14 +122,13 @@ var AbstractAPI = class {
126
122
  };
127
123
 
128
124
  // src/fireRestApi/endpoints/EmailApi.ts
129
- var rootPath = "/customTokens";
130
125
  var EmailApi = class extends AbstractAPI {
131
126
  async verifyEmailVerification(apiKey, params) {
132
127
  this.requireApiKey(apiKey);
133
128
  const { ...restParams } = params;
134
129
  return this.request({
130
+ endpoint: "sendOobCode",
135
131
  method: "POST",
136
- path: `${rootPath}`,
137
132
  bodyParams: restParams
138
133
  });
139
134
  }
@@ -141,22 +136,21 @@ var EmailApi = class extends AbstractAPI {
141
136
  this.requireApiKey(apiKey);
142
137
  const { ...restParams } = params;
143
138
  return this.request({
139
+ endpoint: "sendOobCode",
144
140
  method: "POST",
145
- path: `${rootPath}`,
146
141
  bodyParams: restParams
147
142
  });
148
143
  }
149
144
  };
150
145
 
151
146
  // src/fireRestApi/endpoints/PasswordApi.ts
152
- var rootPath2 = "/customTokens";
153
147
  var PasswordApi = class extends AbstractAPI {
154
148
  async verifyPasswordResetCode(apiKey, params) {
155
149
  this.requireApiKey(apiKey);
156
150
  const { ...restParams } = params;
157
151
  return this.request({
152
+ endpoint: "passwordReset",
158
153
  method: "POST",
159
- path: `${rootPath2}`,
160
154
  bodyParams: restParams
161
155
  });
162
156
  }
@@ -164,8 +158,8 @@ var PasswordApi = class extends AbstractAPI {
164
158
  this.requireApiKey(apiKey);
165
159
  const { ...restParams } = params;
166
160
  return this.request({
161
+ endpoint: "passwordReset",
167
162
  method: "POST",
168
- path: `${rootPath2}`,
169
163
  bodyParams: restParams
170
164
  });
171
165
  }
@@ -173,53 +167,81 @@ var PasswordApi = class extends AbstractAPI {
173
167
  this.requireApiKey(apiKey);
174
168
  const { ...restParams } = params;
175
169
  return this.request({
170
+ endpoint: "passwordReset",
176
171
  method: "POST",
177
- path: `${rootPath2}`,
178
172
  bodyParams: restParams
179
173
  });
180
174
  }
181
175
  };
182
176
 
183
177
  // src/fireRestApi/endpoints/SignInTokenApi.ts
184
- var rootPath3 = "/customTokens";
185
178
  var SignInTokenApi = class extends AbstractAPI {
186
179
  async createCustomToken(apiKey, params) {
187
- this.requireApiKey(apiKey);
188
- const { ...restParams } = params;
189
- return this.request({
190
- method: "POST",
191
- path: `${rootPath3}`,
192
- bodyParams: restParams
193
- });
180
+ try {
181
+ this.requireApiKey(apiKey);
182
+ const { ...restParams } = params;
183
+ const response = await this.request({
184
+ endpoint: "signInWithCustomToken",
185
+ method: "POST",
186
+ bodyParams: restParams
187
+ });
188
+ if (response.errors) {
189
+ const errorMessage = response.errors[0]?.message || "Failed to create custom token";
190
+ throw new Error(errorMessage);
191
+ }
192
+ return response.data;
193
+ } catch (error) {
194
+ const contextualMessage = `Failed to create custom token: ${error instanceof Error ? error.message : "Unknown error"}`;
195
+ throw new Error(contextualMessage);
196
+ }
194
197
  }
195
198
  };
196
199
 
197
200
  // src/fireRestApi/endpoints/SignUpApi.ts
198
- var rootPath4 = "/customTokens";
199
201
  var SignUpApi = class extends AbstractAPI {
200
202
  async createCustomToken(apiKey, params) {
201
203
  this.requireApiKey(apiKey);
202
204
  const { ...restParams } = params;
203
205
  return this.request({
206
+ endpoint: "signUp",
204
207
  method: "POST",
205
- path: `${rootPath4}`,
206
208
  bodyParams: restParams
207
209
  });
208
210
  }
209
211
  };
210
212
 
211
213
  // src/fireRestApi/endpoints/TokenApi.ts
212
- var rootPath5 = "/sessions";
213
214
  var TokenApi = class extends AbstractAPI {
214
215
  async refreshToken(apiKey, params) {
215
216
  this.requireApiKey(apiKey);
216
217
  const { ...restParams } = params;
217
218
  return this.request({
219
+ endpoint: "refreshToken",
218
220
  method: "POST",
219
- path: `${rootPath5}/refresh`,
220
221
  bodyParams: restParams
221
222
  });
222
223
  }
224
+ async exchangeCustomForIdAndRefreshTokens(apiKey, params) {
225
+ try {
226
+ this.requireApiKey(apiKey);
227
+ const { ...restParams } = params;
228
+ const response = await this.request({
229
+ endpoint: "signInWithCustomToken",
230
+ method: "POST",
231
+ apiKey,
232
+ bodyParams: restParams
233
+ });
234
+ if (response.errors) {
235
+ const errorMessage = response.errors[0]?.message || "Failed to create custom token";
236
+ console.error("Error response from exchangeCustomForIdAndRefreshTokens:", response.errors);
237
+ throw new Error(errorMessage);
238
+ }
239
+ return response.data;
240
+ } catch (error) {
241
+ const contextualMessage = `Failed to create custom token: ${error instanceof Error ? error.message : "Unknown error"}`;
242
+ throw new Error(contextualMessage);
243
+ }
244
+ }
223
245
  };
224
246
 
225
247
  // src/runtime.ts
@@ -238,20 +260,65 @@ var runtime = {
238
260
  Response: globalThis.Response
239
261
  };
240
262
 
241
- // src/utils/path.ts
242
- var SEPARATOR = "/";
243
- var MULTIPLE_SEPARATOR_REGEX = new RegExp("(?<!:)" + SEPARATOR + "{1,}", "g");
244
- function joinPaths(...args) {
245
- return args.filter((p) => p).join(SEPARATOR).replace(MULTIPLE_SEPARATOR_REGEX, SEPARATOR);
263
+ // src/fireRestApi/emulator.ts
264
+ var FIREBASE_AUTH_EMULATOR_HOST = process.env.FIREBASE_AUTH_EMULATOR_HOST;
265
+ function emulatorHost() {
266
+ if (typeof process === "undefined") return void 0;
267
+ return FIREBASE_AUTH_EMULATOR_HOST;
268
+ }
269
+ function useEmulator() {
270
+ return !!emulatorHost();
246
271
  }
247
272
 
273
+ // src/fireRestApi/endpointUrl.ts
274
+ var getRefreshTokenEndpoint = (apiKey) => {
275
+ return `https://securetoken.googleapis.com/v1/token?key=${apiKey}`;
276
+ };
277
+ var signInWithPassword = (apiKey) => {
278
+ return `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${apiKey}`;
279
+ };
280
+ var signUpEndpoint = (apiKey) => {
281
+ return `https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${apiKey}`;
282
+ };
283
+ var getCustomTokenEndpoint = (apiKey) => {
284
+ if (useEmulator() && process.env.FIREBASE_AUTH_EMULATOR_HOST) {
285
+ let protocol = "http://";
286
+ if (process.env.FIREBASE_AUTH_EMULATOR_HOST.startsWith("http://")) {
287
+ protocol = "";
288
+ }
289
+ return `${protocol}${process.env.FIREBASE_AUTH_EMULATOR_HOST}/identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=${apiKey}`;
290
+ }
291
+ return `https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=${apiKey}`;
292
+ };
293
+ var passwordResetEndpoint = (apiKey) => {
294
+ return `https://identitytoolkit.googleapis.com/v1/accounts:resetPassword?key=${apiKey}`;
295
+ };
296
+
248
297
  // src/fireRestApi/request.ts
298
+ var FIREBASE_ENDPOINT_MAP = {
299
+ refreshToken: getRefreshTokenEndpoint,
300
+ signInWithPassword,
301
+ signUp: signUpEndpoint,
302
+ signInWithCustomToken: getCustomTokenEndpoint,
303
+ passwordReset: passwordResetEndpoint,
304
+ sendOobCode: signInWithPassword
305
+ };
249
306
  function createRequest(options) {
250
307
  const requestFn = async (requestOptions) => {
251
- const { apiKey, apiUrl, apiVersion = "v1" } = options;
252
- const { path, method, queryParams, headerParams, bodyParams, formData } = requestOptions;
253
- const url = joinPaths(apiUrl, apiVersion, path);
254
- const finalUrl = new URL(url);
308
+ const { endpoint, method, apiKey, queryParams, headerParams, bodyParams, formData } = requestOptions;
309
+ if (!apiKey) {
310
+ return {
311
+ data: null,
312
+ errors: [
313
+ {
314
+ code: "missing_api_key",
315
+ message: "Firebase API key is required"
316
+ }
317
+ ]
318
+ };
319
+ }
320
+ const endpointUrl = FIREBASE_ENDPOINT_MAP[endpoint](apiKey);
321
+ const finalUrl = new URL(endpointUrl);
255
322
  if (queryParams) {
256
323
  Object.entries(queryParams).forEach(([key, value]) => {
257
324
  if (value) {
@@ -342,8 +409,12 @@ function createFireApi(options) {
342
409
  };
343
410
  }
344
411
 
412
+ // src/tokens/request.ts
413
+ import { getCookieName, getCookiePrefix } from "@tern-secure/shared/cookie";
414
+
345
415
  // src/utils/options.ts
346
416
  var defaultOptions = {
417
+ apiKey: void 0,
347
418
  apiUrl: void 0,
348
419
  apiVersion: void 0
349
420
  };
@@ -354,131 +425,6 @@ function mergePreDefinedOptions(userOptions = {}) {
354
425
  };
355
426
  }
356
427
 
357
- // src/tokens/keys.ts
358
- var cache = {};
359
- var lastUpdatedAt = 0;
360
- var googleExpiresAt = 0;
361
- function getFromCache(kid) {
362
- return cache[kid];
363
- }
364
- function getCacheValues() {
365
- return Object.values(cache);
366
- }
367
- function setInCache(kid, certificate, shouldExpire = true) {
368
- cache[kid] = certificate;
369
- lastUpdatedAt = shouldExpire ? Date.now() : -1;
370
- }
371
- async function fetchPublicKeys(keyUrl) {
372
- const url = new URL(keyUrl);
373
- const response = await fetch(url);
374
- if (!response.ok) {
375
- throw new TokenVerificationError({
376
- message: `Error loading public keys from ${url.href} with code=${response.status} `,
377
- reason: TokenVerificationErrorReason.TokenInvalid
378
- });
379
- }
380
- const data = await response.json();
381
- const expiresAt = getExpiresAt(response);
382
- return {
383
- keys: data,
384
- expiresAt
385
- };
386
- }
387
- async function loadJWKFromRemote({
388
- keyURL = SESSION_COOKIE_PUBLIC_KEYS_URL,
389
- skipJwksCache,
390
- kid
391
- }) {
392
- if (skipJwksCache || isCacheExpired() || !getFromCache(kid)) {
393
- const { keys, expiresAt } = await fetchPublicKeys(keyURL);
394
- if (!keys || Object.keys(keys).length === 0) {
395
- throw new TokenVerificationError({
396
- message: `The JWKS endpoint ${keyURL} returned no keys`,
397
- reason: TokenVerificationErrorReason.RemoteJWKFailedToLoad
398
- });
399
- }
400
- googleExpiresAt = expiresAt;
401
- Object.entries(keys).forEach(([keyId, cert2]) => {
402
- setInCache(keyId, cert2);
403
- });
404
- }
405
- const cert = getFromCache(kid);
406
- if (!cert) {
407
- getCacheValues();
408
- const availableKids = Object.keys(cache).sort().join(", ");
409
- throw new TokenVerificationError({
410
- message: `No public key found for kid "${kid}". Available kids: [${availableKids}]`,
411
- reason: TokenVerificationErrorReason.TokenInvalid
412
- });
413
- }
414
- return cert;
415
- }
416
- function isCacheExpired() {
417
- const now = Date.now();
418
- if (lastUpdatedAt === -1) {
419
- return false;
420
- }
421
- const cacheAge = now - lastUpdatedAt;
422
- const maxCacheAge = MAX_CACHE_LAST_UPDATED_AT_SECONDS * 1e3;
423
- const localCacheExpired = cacheAge >= maxCacheAge;
424
- const googleCacheExpired = now >= googleExpiresAt;
425
- const isExpired = localCacheExpired || googleCacheExpired;
426
- if (isExpired) {
427
- cache = {};
428
- }
429
- return isExpired;
430
- }
431
- function getExpiresAt(res) {
432
- const cacheControlHeader = res.headers.get("cache-control");
433
- if (!cacheControlHeader) {
434
- return Date.now() + DEFAULT_CACHE_DURATION;
435
- }
436
- const maxAgeMatch = cacheControlHeader.match(CACHE_CONTROL_REGEX);
437
- const maxAge = maxAgeMatch ? parseInt(maxAgeMatch[1], 10) : DEFAULT_CACHE_DURATION / 1e3;
438
- return Date.now() + maxAge * 1e3;
439
- }
440
-
441
- // src/tokens/verify.ts
442
- async function verifyToken(token, options) {
443
- const { data: decodedResult, errors } = ternDecodeJwt(token);
444
- if (errors) {
445
- return { errors };
446
- }
447
- const { header } = decodedResult;
448
- const { kid } = header;
449
- if (!kid) {
450
- return {
451
- errors: [
452
- new TokenVerificationError({
453
- reason: TokenVerificationErrorReason.TokenInvalid,
454
- message: 'JWT "kid" header is missing.'
455
- })
456
- ]
457
- };
458
- }
459
- try {
460
- const key = options.jwtKey || await loadJWKFromRemote({ ...options, kid });
461
- if (!key) {
462
- return {
463
- errors: [
464
- new TokenVerificationError({
465
- reason: TokenVerificationErrorReason.TokenInvalid,
466
- message: `No public key found for kid "${kid}".`
467
- })
468
- ]
469
- };
470
- }
471
- return await verifyJwt(token, { ...options, key });
472
- } catch (error) {
473
- if (error instanceof TokenVerificationError) {
474
- return { errors: [error] };
475
- }
476
- return {
477
- errors: [error]
478
- };
479
- }
480
- }
481
-
482
428
  // src/tokens/request.ts
483
429
  var BEARER_PREFIX = "Bearer ";
484
430
  function extractTokenFromHeader(request) {
@@ -493,6 +439,11 @@ function extractTokenFromCookie(request) {
493
439
  if (!cookieHeader) {
494
440
  return null;
495
441
  }
442
+ const cookiePrefix = getCookiePrefix();
443
+ const idTokenCookieName = getCookieName(
444
+ constants.Cookies.IdToken,
445
+ cookiePrefix
446
+ );
496
447
  const cookies = cookieHeader.split(";").reduce(
497
448
  (acc, cookie) => {
498
449
  const [name, value] = cookie.trim().split("=");
@@ -501,7 +452,7 @@ function extractTokenFromCookie(request) {
501
452
  },
502
453
  {}
503
454
  );
504
- return cookies[constants.Cookies.Session] || null;
455
+ return idTokenCookieName || null;
505
456
  }
506
457
  function hasAuthorizationHeader(request) {
507
458
  return request.headers.has("Authorization");