@tern-secure/backend 1.2.0-canary.v20251125170702 → 1.2.0-canary.v20251127235234

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 (62) hide show
  1. package/dist/admin/index.js +3 -0
  2. package/dist/admin/index.js.map +1 -1
  3. package/dist/admin/index.mjs +4 -2
  4. package/dist/admin/index.mjs.map +1 -1
  5. package/dist/auth/constants.d.ts +6 -0
  6. package/dist/auth/constants.d.ts.map +1 -0
  7. package/dist/auth/credential.d.ts +27 -0
  8. package/dist/auth/credential.d.ts.map +1 -0
  9. package/dist/auth/getauth.d.ts +1 -0
  10. package/dist/auth/getauth.d.ts.map +1 -1
  11. package/dist/auth/index.js +234 -28
  12. package/dist/auth/index.js.map +1 -1
  13. package/dist/auth/index.mjs +3 -3
  14. package/dist/auth/utils.d.ts +3 -0
  15. package/dist/auth/utils.d.ts.map +1 -0
  16. package/dist/{chunk-MS6L7M3C.mjs → chunk-DJLDUW7J.mjs} +174 -12
  17. package/dist/chunk-DJLDUW7J.mjs.map +1 -0
  18. package/dist/{chunk-ASGV4MFO.mjs → chunk-GFH5CXQR.mjs} +2 -2
  19. package/dist/{chunk-DDUNOEIM.mjs → chunk-NXYWC6YO.mjs} +278 -116
  20. package/dist/chunk-NXYWC6YO.mjs.map +1 -0
  21. package/dist/{chunk-DFAJCSBJ.mjs → chunk-WIVOBOZR.mjs} +2 -1
  22. package/dist/chunk-WIVOBOZR.mjs.map +1 -0
  23. package/dist/constants.d.ts +1 -0
  24. package/dist/constants.d.ts.map +1 -1
  25. package/dist/fireRestApi/createFireApi.d.ts +2 -1
  26. package/dist/fireRestApi/createFireApi.d.ts.map +1 -1
  27. package/dist/fireRestApi/endpoints/AppCheckApi.d.ts +23 -0
  28. package/dist/fireRestApi/endpoints/AppCheckApi.d.ts.map +1 -0
  29. package/dist/fireRestApi/endpoints/TokenApi.d.ts +3 -1
  30. package/dist/fireRestApi/endpoints/TokenApi.d.ts.map +1 -1
  31. package/dist/fireRestApi/endpoints/UserData.d.ts.map +1 -1
  32. package/dist/fireRestApi/endpoints/index.d.ts +1 -0
  33. package/dist/fireRestApi/endpoints/index.d.ts.map +1 -1
  34. package/dist/fireRestApi/request.d.ts.map +1 -1
  35. package/dist/index.js +390 -36
  36. package/dist/index.js.map +1 -1
  37. package/dist/index.mjs +161 -14
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/jwt/index.d.ts +1 -0
  40. package/dist/jwt/index.d.ts.map +1 -1
  41. package/dist/jwt/index.js +51 -19
  42. package/dist/jwt/index.js.map +1 -1
  43. package/dist/jwt/index.mjs +8 -132
  44. package/dist/jwt/index.mjs.map +1 -1
  45. package/dist/jwt/signJwt.d.ts +8 -0
  46. package/dist/jwt/signJwt.d.ts.map +1 -1
  47. package/dist/jwt/verifyJwt.d.ts.map +1 -1
  48. package/dist/tokens/authstate.d.ts.map +1 -1
  49. package/dist/tokens/c-authenticateRequestProcessor.d.ts +1 -0
  50. package/dist/tokens/c-authenticateRequestProcessor.d.ts.map +1 -1
  51. package/dist/tokens/request.d.ts.map +1 -1
  52. package/dist/tokens/types.d.ts +2 -1
  53. package/dist/tokens/types.d.ts.map +1 -1
  54. package/dist/tokens/verify.d.ts +2 -2
  55. package/dist/tokens/verify.d.ts.map +1 -1
  56. package/dist/utils/admin-init.d.ts +1 -0
  57. package/dist/utils/admin-init.d.ts.map +1 -1
  58. package/package.json +3 -3
  59. package/dist/chunk-DDUNOEIM.mjs.map +0 -1
  60. package/dist/chunk-DFAJCSBJ.mjs.map +0 -1
  61. package/dist/chunk-MS6L7M3C.mjs.map +0 -1
  62. /package/dist/{chunk-ASGV4MFO.mjs.map → chunk-GFH5CXQR.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -78,6 +78,7 @@ var QueryParameters = {
78
78
  };
79
79
  var Headers2 = {
80
80
  Accept: "accept",
81
+ AppCheckToken: "x-firebase-appcheck",
81
82
  AuthMessage: "x-ternsecure-auth-message",
82
83
  Authorization: "authorization",
83
84
  AuthReason: "x-ternsecure-auth-reason",
@@ -371,6 +372,84 @@ var AbstractAPI = class {
371
372
  }
372
373
  };
373
374
 
375
+ // src/fireRestApi/endpoints/AppCheckApi.ts
376
+ function getSdkVersion() {
377
+ return "12.7.0";
378
+ }
379
+ var FIREBASE_APP_CHECK_CONFIG_HEADERS = {
380
+ "X-Firebase-Client": `fire-admin-node/${getSdkVersion()}`
381
+ };
382
+ var AppCheckApi = class extends AbstractAPI {
383
+ async exchangeCustomToken(params) {
384
+ const { projectId, appId, customToken, accessToken, limitedUse = false } = params;
385
+ if (!projectId || !appId) {
386
+ throw new Error("Project ID and App ID are required for App Check token exchange");
387
+ }
388
+ const endpoint = `https://firebaseappcheck.googleapis.com/v1beta/projects/${projectId}/apps/${appId}:exchangeCustomToken`;
389
+ const headers = {
390
+ "Content-Type": "application/json",
391
+ "Authorization": `Bearer ${accessToken}`
392
+ };
393
+ const body = {
394
+ customToken,
395
+ limitedUse
396
+ };
397
+ try {
398
+ const response = await fetch(endpoint, {
399
+ method: "POST",
400
+ headers,
401
+ body: JSON.stringify(body)
402
+ });
403
+ if (!response.ok) {
404
+ const errorText = await response.text();
405
+ throw new Error(`App Check token exchange failed: ${response.status} ${errorText}`);
406
+ }
407
+ const data = await response.json();
408
+ return {
409
+ token: data.token,
410
+ ttl: data.ttl
411
+ };
412
+ } catch (error) {
413
+ console.warn("[ternsecure - appcheck api]unexpected error:", error);
414
+ throw error;
415
+ }
416
+ }
417
+ async exchangeDebugToken(params) {
418
+ const { projectId, appId, customToken, accessToken, limitedUse = false } = params;
419
+ if (!projectId || !appId) {
420
+ throw new Error("Project ID and App ID are required for App Check token exchange");
421
+ }
422
+ const endpoint = `https://firebaseappcheck.googleapis.com/v1beta/projects/${projectId}/apps/${appId}:exchangeDebugToken`;
423
+ const headers = {
424
+ ...FIREBASE_APP_CHECK_CONFIG_HEADERS,
425
+ "Authorization": `Bearer ${accessToken}`
426
+ };
427
+ const body = {
428
+ customToken,
429
+ limitedUse
430
+ };
431
+ try {
432
+ const response = await fetch(endpoint, {
433
+ method: "POST",
434
+ headers,
435
+ body: JSON.stringify(body)
436
+ });
437
+ if (!response.ok) {
438
+ const errorText = await response.text();
439
+ throw new Error(`App Check token exchange failed: ${response.status} ${errorText}`);
440
+ }
441
+ const data = await response.json();
442
+ return {
443
+ token: data.token,
444
+ ttl: data.ttl
445
+ };
446
+ } catch (error) {
447
+ console.warn("[ternsecure - appcheck api]unexpected error:", error);
448
+ throw error;
449
+ }
450
+ }
451
+ };
452
+
374
453
  // src/fireRestApi/endpoints/EmailApi.ts
375
454
  var EmailApi = class extends AbstractAPI {
376
455
  async verifyEmailVerification(apiKey, params) {
@@ -488,11 +567,14 @@ var SignUpApi = class extends AbstractAPI {
488
567
  var TokenApi = class extends AbstractAPI {
489
568
  async refreshToken(apiKey, params) {
490
569
  this.requireApiKey(apiKey);
491
- const { refresh_token, request_origin, ...restParams } = params;
570
+ const { refresh_token, request_origin, app_check_token, ...restParams } = params;
492
571
  const headers = {};
493
572
  if (request_origin) {
494
573
  headers["Referer"] = request_origin;
495
574
  }
575
+ if (app_check_token) {
576
+ headers["X-Firebase-AppCheck"] = app_check_token;
577
+ }
496
578
  const bodyParams = {
497
579
  grant_type: "refresh_token",
498
580
  refresh_token,
@@ -512,13 +594,23 @@ var TokenApi = class extends AbstractAPI {
512
594
  if (options?.referer) {
513
595
  headers["Referer"] = options.referer;
514
596
  }
515
- return this.request({
597
+ if (options?.appCheckToken) {
598
+ headers["X-Firebase-AppCheck"] = options.appCheckToken;
599
+ }
600
+ const response = await this.request({
516
601
  endpoint: "signInWithCustomToken",
517
602
  method: "POST",
518
603
  apiKey,
519
604
  bodyParams: params,
520
605
  headerParams: headers
521
606
  });
607
+ if (response.errors) {
608
+ throw new Error(response.errors[0].message);
609
+ }
610
+ if (!response.data) {
611
+ throw new Error("No data received from Firebase token exchange");
612
+ }
613
+ return response.data;
522
614
  }
523
615
  };
524
616
 
@@ -650,8 +742,18 @@ function createRequest(options) {
650
742
  ...body
651
743
  });
652
744
  }
653
- const isJSONResponse = res?.headers && res.headers?.get(constants.Headers.ContentType) === constants.ContentTypes.Json;
654
- const responseBody = await (isJSONResponse ? res.json() : res.text());
745
+ const isJSONResponse = res?.headers && res.headers?.get(constants.Headers.ContentType)?.includes(constants.ContentTypes.Json);
746
+ let responseBody;
747
+ try {
748
+ const text = await res.text();
749
+ try {
750
+ responseBody = JSON.parse(text);
751
+ } catch {
752
+ responseBody = text;
753
+ }
754
+ } catch (e) {
755
+ responseBody = null;
756
+ }
655
757
  if (!res.ok) {
656
758
  return {
657
759
  data: null,
@@ -732,6 +834,7 @@ function parseError(error) {
732
834
  function createFireApi(options) {
733
835
  const request = createRequest(options);
734
836
  return {
837
+ appCheck: new AppCheckApi(request),
735
838
  email: new EmailApi(request),
736
839
  password: new PasswordApi(request),
737
840
  signIn: new SignInApi(request),
@@ -1094,33 +1197,44 @@ async function verifySignature(jwt, key) {
1094
1197
  }
1095
1198
  }
1096
1199
  function ternDecodeJwt(token) {
1097
- const header = (0, import_jose3.decodeProtectedHeader)(token);
1098
- const payload = (0, import_jose3.decodeJwt)(token);
1099
- const tokenParts = (token || "").toString().split(".");
1100
- if (tokenParts.length !== 3) {
1200
+ try {
1201
+ const header = (0, import_jose3.decodeProtectedHeader)(token);
1202
+ const payload = (0, import_jose3.decodeJwt)(token);
1203
+ const tokenParts = (token || "").toString().split(".");
1204
+ if (tokenParts.length !== 3) {
1205
+ return {
1206
+ errors: [
1207
+ new TokenVerificationError({
1208
+ reason: TokenVerificationErrorReason.TokenInvalid,
1209
+ message: "Invalid JWT format"
1210
+ })
1211
+ ]
1212
+ };
1213
+ }
1214
+ const [rawHeader, rawPayload, rawSignature] = tokenParts;
1215
+ const signature = base64url.parse(rawSignature, { loose: true });
1216
+ const data = {
1217
+ header,
1218
+ payload,
1219
+ signature,
1220
+ raw: {
1221
+ header: rawHeader,
1222
+ payload: rawPayload,
1223
+ signature: rawSignature,
1224
+ text: token
1225
+ }
1226
+ };
1227
+ return { data };
1228
+ } catch (error) {
1101
1229
  return {
1102
1230
  errors: [
1103
1231
  new TokenVerificationError({
1104
1232
  reason: TokenVerificationErrorReason.TokenInvalid,
1105
- message: "Invalid JWT format"
1233
+ message: `${error.message || "Invalid Token or Protected Header formatting"} (Token length: ${token?.length}, First 10 chars: ${token?.substring(0, 10)}...)`
1106
1234
  })
1107
1235
  ]
1108
1236
  };
1109
1237
  }
1110
- const [rawHeader, rawPayload, rawSignature] = tokenParts;
1111
- const signature = base64url.parse(rawSignature, { loose: true });
1112
- const data = {
1113
- header,
1114
- payload,
1115
- signature,
1116
- raw: {
1117
- header: rawHeader,
1118
- payload: rawPayload,
1119
- signature: rawSignature,
1120
- text: token
1121
- }
1122
- };
1123
- return { data };
1124
1238
  }
1125
1239
  async function verifyJwt(token, options) {
1126
1240
  const { key } = options;
@@ -1278,6 +1392,143 @@ async function verifyToken(token, options) {
1278
1392
  }
1279
1393
  }
1280
1394
 
1395
+ // src/jwt/guardReturn.ts
1396
+ function createJwtGuard(decodedFn) {
1397
+ return (...args) => {
1398
+ const { data, errors } = decodedFn(...args);
1399
+ if (errors) {
1400
+ throw errors[0];
1401
+ }
1402
+ return data;
1403
+ };
1404
+ }
1405
+
1406
+ // src/jwt/jwt.ts
1407
+ var import_jose4 = require("jose");
1408
+
1409
+ // src/jwt/signJwt.ts
1410
+ var import_jose5 = require("jose");
1411
+ var ALGORITHM_RS256 = "RS256";
1412
+ async function ternSignJwt(opts) {
1413
+ const { payload, privateKey, keyId } = opts;
1414
+ let key;
1415
+ try {
1416
+ key = await (0, import_jose5.importPKCS8)(privateKey, ALGORITHM_RS256);
1417
+ } catch (error) {
1418
+ throw new TokenVerificationError({
1419
+ message: `Failed to import private key: ${error.message}`,
1420
+ reason: TokenVerificationErrorReason.TokenInvalid
1421
+ });
1422
+ }
1423
+ return new import_jose5.SignJWT(payload).setProtectedHeader({ alg: ALGORITHM_RS256, kid: keyId }).sign(key);
1424
+ }
1425
+
1426
+ // src/jwt/index.ts
1427
+ var ternDecodeJwt2 = createJwtGuard(ternDecodeJwt);
1428
+
1429
+ // src/auth/constants.ts
1430
+ var TOKEN_EXPIRY_THRESHOLD_MILLIS = 5 * 60 * 1e3;
1431
+ var GOOGLE_TOKEN_AUDIENCE = "https://accounts.google.com/o/oauth2/token";
1432
+ var GOOGLE_AUTH_TOKEN_HOST = "accounts.google.com";
1433
+ var GOOGLE_AUTH_TOKEN_PATH = "/o/oauth2/token";
1434
+ var ONE_HOUR_IN_SECONDS = 60 * 60;
1435
+
1436
+ // src/auth/utils.ts
1437
+ async function getDetailFromResponse(response) {
1438
+ const json = await response.json();
1439
+ if (!json) {
1440
+ return "Missing error payload";
1441
+ }
1442
+ let detail = typeof json.error === "string" ? json.error : json.error?.message ?? "Missing error payload";
1443
+ if (json.error_description) {
1444
+ detail += " (" + json.error_description + ")";
1445
+ }
1446
+ return detail;
1447
+ }
1448
+ async function fetchJson(url, init) {
1449
+ return (await fetchAny(url, init)).json();
1450
+ }
1451
+ async function fetchAny(url, init) {
1452
+ const response = await fetch(url, init);
1453
+ if (!response.ok) {
1454
+ throw new Error(await getDetailFromResponse(response));
1455
+ }
1456
+ return response;
1457
+ }
1458
+
1459
+ // src/auth/credential.ts
1460
+ var accessTokenCache = /* @__PURE__ */ new Map();
1461
+ async function requestAccessToken(urlString, init) {
1462
+ const json = await fetchJson(urlString, init);
1463
+ if (!json.access_token || !json.expires_in) {
1464
+ throw new Error("Invalid access token response");
1465
+ }
1466
+ return {
1467
+ accessToken: json.access_token,
1468
+ expirationTime: Date.now() + json.expires_in * 1e3
1469
+ };
1470
+ }
1471
+ var ServiceAccountTokenManager = class {
1472
+ projectId;
1473
+ privateKey;
1474
+ clientEmail;
1475
+ constructor(serviceAccount) {
1476
+ this.projectId = serviceAccount.projectId;
1477
+ this.privateKey = serviceAccount.privateKey;
1478
+ this.clientEmail = serviceAccount.clientEmail;
1479
+ }
1480
+ fetchAccessToken = async (url) => {
1481
+ const token = await this.createJwt();
1482
+ const postData = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + token;
1483
+ return requestAccessToken(url, {
1484
+ method: "POST",
1485
+ headers: {
1486
+ "Content-Type": "application/x-www-form-urlencoded",
1487
+ Authorization: `Bearer ${token}`,
1488
+ Accept: "application/json"
1489
+ },
1490
+ body: postData
1491
+ });
1492
+ };
1493
+ fetchAndCacheAccessToken = async (url) => {
1494
+ const accessToken = await this.fetchAccessToken(url);
1495
+ accessTokenCache.set(this.projectId, accessToken);
1496
+ return accessToken;
1497
+ };
1498
+ getAccessToken = async (refresh) => {
1499
+ const url = `https://${GOOGLE_AUTH_TOKEN_HOST}${GOOGLE_AUTH_TOKEN_PATH}`;
1500
+ if (refresh) {
1501
+ return this.fetchAndCacheAccessToken(url);
1502
+ }
1503
+ const cachedResponse = accessTokenCache.get(this.projectId);
1504
+ if (!cachedResponse || cachedResponse.expirationTime - Date.now() <= TOKEN_EXPIRY_THRESHOLD_MILLIS) {
1505
+ return this.fetchAndCacheAccessToken(url);
1506
+ }
1507
+ return cachedResponse;
1508
+ };
1509
+ createJwt = async () => {
1510
+ const iat = Math.floor(Date.now() / 1e3);
1511
+ const payload = {
1512
+ aud: GOOGLE_TOKEN_AUDIENCE,
1513
+ iat,
1514
+ exp: iat + ONE_HOUR_IN_SECONDS,
1515
+ iss: this.clientEmail,
1516
+ sub: this.clientEmail,
1517
+ scope: [
1518
+ "https://www.googleapis.com/auth/cloud-platform",
1519
+ "https://www.googleapis.com/auth/firebase.database",
1520
+ "https://www.googleapis.com/auth/firebase.messaging",
1521
+ "https://www.googleapis.com/auth/identitytoolkit",
1522
+ "https://www.googleapis.com/auth/userinfo.email"
1523
+ ].join(" ")
1524
+ };
1525
+ return ternSignJwt({
1526
+ payload,
1527
+ privateKey: this.privateKey
1528
+ });
1529
+ };
1530
+ };
1531
+
1281
1532
  // src/auth/getauth.ts
1282
1533
  var API_KEY_ERROR = "API Key is required";
1283
1534
  var NO_DATA_ERROR = "No token data received";
@@ -1292,9 +1543,17 @@ function parseFirebaseResponse(data) {
1292
1543
  return data;
1293
1544
  }
1294
1545
  function getAuth(options) {
1295
- const { apiKey } = options;
1546
+ const { apiKey, firebaseAdminConfig } = options;
1296
1547
  const firebaseApiKey = options.firebaseConfig?.apiKey;
1297
1548
  const effectiveApiKey = apiKey || firebaseApiKey;
1549
+ let credential = null;
1550
+ if (firebaseAdminConfig?.projectId && firebaseAdminConfig?.privateKey && firebaseAdminConfig?.clientEmail) {
1551
+ credential = new ServiceAccountTokenManager({
1552
+ projectId: firebaseAdminConfig.projectId,
1553
+ privateKey: firebaseAdminConfig.privateKey,
1554
+ clientEmail: firebaseAdminConfig.clientEmail
1555
+ });
1556
+ }
1298
1557
  async function getUserData(idToken, localId) {
1299
1558
  if (!effectiveApiKey) {
1300
1559
  throw new Error(API_KEY_ERROR);
@@ -1336,23 +1595,23 @@ function getAuth(options) {
1336
1595
  if (!effectiveApiKey) {
1337
1596
  throw new Error("API Key is required to create custom token");
1338
1597
  }
1339
- const response = await options.apiClient?.tokens.exchangeCustomForIdAndRefreshTokens(
1598
+ const data = await options.apiClient?.tokens.exchangeCustomForIdAndRefreshTokens(
1340
1599
  effectiveApiKey,
1341
1600
  {
1342
1601
  token: customToken,
1343
1602
  returnSecureToken: true
1344
1603
  },
1345
1604
  {
1346
- referer: opts.referer
1605
+ referer: opts.referer,
1606
+ appCheckToken: opts.appCheckToken
1347
1607
  }
1348
1608
  );
1349
- if (!response?.data) {
1609
+ if (!data) {
1350
1610
  throw new Error("No data received from Firebase token exchange");
1351
1611
  }
1352
- const parsedData = parseFirebaseResponse(response.data);
1353
1612
  return {
1354
- idToken: parsedData.idToken,
1355
- refreshToken: parsedData.refreshToken
1613
+ idToken: data.idToken,
1614
+ refreshToken: data.refreshToken
1356
1615
  };
1357
1616
  }
1358
1617
  async function createCustomIdAndRefreshToken(idToken, opts) {
@@ -1366,7 +1625,8 @@ function getAuth(options) {
1366
1625
  source_sign_in_provider: data.firebase.sign_in_provider
1367
1626
  });
1368
1627
  const idAndRefreshTokens = await customForIdAndRefreshToken(customToken, {
1369
- referer: opts.referer
1628
+ referer: opts.referer,
1629
+ appCheckToken: opts.appCheckToken
1370
1630
  });
1371
1631
  const decodedCustomIdToken = await verifyToken(idAndRefreshTokens.idToken, options);
1372
1632
  if (decodedCustomIdToken.errors) {
@@ -1378,11 +1638,60 @@ function getAuth(options) {
1378
1638
  auth_time: decodedCustomIdToken.data.auth_time
1379
1639
  };
1380
1640
  }
1641
+ async function exchangeAppCheckToken(idToken) {
1642
+ if (!credential) {
1643
+ return {
1644
+ data: null,
1645
+ error: new Error(
1646
+ "Firebase Admin config must be provided to exchange App Check tokens."
1647
+ )
1648
+ };
1649
+ }
1650
+ if (!effectiveApiKey) {
1651
+ return { data: null, error: new Error(API_KEY_ERROR) };
1652
+ }
1653
+ try {
1654
+ const decoded = await verifyToken(idToken, options);
1655
+ if (decoded.errors) {
1656
+ return { data: null, error: decoded.errors[0] };
1657
+ }
1658
+ const customToken = await createCustomToken(decoded.data.uid, {
1659
+ emailVerified: decoded.data.email_verified,
1660
+ source_sign_in_provider: decoded.data.firebase.sign_in_provider
1661
+ });
1662
+ const projectId = options.firebaseConfig?.projectId;
1663
+ const appId = options.firebaseConfig?.appId;
1664
+ if (!projectId || !appId) {
1665
+ return { data: null, error: new Error("Project ID and App ID are required for App Check") };
1666
+ }
1667
+ const { accessToken } = await credential.getAccessToken();
1668
+ const appCheckResponse = await options.apiClient?.appCheck.exchangeCustomToken({
1669
+ accessToken,
1670
+ projectId,
1671
+ appId,
1672
+ customToken,
1673
+ limitedUse: false
1674
+ });
1675
+ if (!appCheckResponse?.token) {
1676
+ return { data: null, error: new Error("Failed to exchange for App Check token") };
1677
+ }
1678
+ return {
1679
+ data: {
1680
+ token: appCheckResponse.token,
1681
+ ttl: appCheckResponse.ttl
1682
+ },
1683
+ error: null
1684
+ };
1685
+ } catch (error) {
1686
+ return { data: null, error };
1687
+ }
1688
+ }
1381
1689
  return {
1382
1690
  getUserData,
1383
1691
  customForIdAndRefreshToken,
1384
1692
  createCustomIdAndRefreshToken,
1385
- refreshExpiredIdToken
1693
+ refreshExpiredIdToken,
1694
+ exchangeAppCheckToken
1386
1695
  };
1387
1696
  }
1388
1697
 
@@ -1413,6 +1722,7 @@ var RequestProcessorContext = class {
1413
1722
  this.userAgent = this.getHeader(constants.Headers.UserAgent);
1414
1723
  this.secFetchDest = this.getHeader(constants.Headers.SecFetchDest);
1415
1724
  this.accept = this.getHeader(constants.Headers.Accept);
1725
+ this.appCheckToken = this.getHeader(constants.Headers.AppCheckToken);
1416
1726
  }
1417
1727
  initCookieValues() {
1418
1728
  const isProduction = process.env.NODE_ENV === "production";
@@ -1476,7 +1786,7 @@ function isRequestForRefresh(error, context, request) {
1476
1786
  }
1477
1787
  async function authenticateRequest(request, options) {
1478
1788
  const context = createRequestProcessor(createTernSecureRequest(request), options);
1479
- const { refreshTokenInCookie } = context;
1789
+ const { refreshTokenInCookie, appCheckToken } = context;
1480
1790
  const { refreshExpiredIdToken } = getAuth(options);
1481
1791
  function checkSessionTimeout(authTimeValue) {
1482
1792
  const defaultMaxAgeSeconds = convertToSeconds("5 days");
@@ -1499,7 +1809,8 @@ async function authenticateRequest(request, options) {
1499
1809
  };
1500
1810
  }
1501
1811
  return await refreshExpiredIdToken(refreshTokenInCookie, {
1502
- referer: context.ternUrl.origin
1812
+ referer: context.ternUrl.origin,
1813
+ appCheckToken
1503
1814
  });
1504
1815
  }
1505
1816
  async function handleRefresh() {
@@ -1601,7 +1912,24 @@ async function authenticateRequest(request, options) {
1601
1912
  if (errors) {
1602
1913
  throw errors[0];
1603
1914
  }
1604
- const signedInRequestState = signedIn(context, data, void 0, context.idTokenInCookie);
1915
+ const { exchangeAppCheckToken } = getAuth(options);
1916
+ let appCheckTokenValue;
1917
+ try {
1918
+ const idToken = context.idTokenInCookie || "";
1919
+ const appCheckResult = await exchangeAppCheckToken(idToken);
1920
+ console.log("[authenticateRequest] App Check exchange result:", appCheckResult);
1921
+ if (appCheckResult.data?.token) {
1922
+ appCheckTokenValue = appCheckResult.data.token;
1923
+ }
1924
+ } catch (error) {
1925
+ console.warn("App Check token exchange failed:", error);
1926
+ }
1927
+ const headers = new Headers();
1928
+ headers.set(
1929
+ constants.Headers.AppCheckToken,
1930
+ appCheckTokenValue || ""
1931
+ );
1932
+ const signedInRequestState = signedIn(context, data, headers, context.idTokenInCookie);
1605
1933
  return signedInRequestState;
1606
1934
  } catch (err) {
1607
1935
  return handleError(err, "cookie");
@@ -1615,7 +1943,23 @@ async function authenticateRequest(request, options) {
1615
1943
  if (errors) {
1616
1944
  throw errors[0];
1617
1945
  }
1618
- const signedInRequestState = signedIn(context, data, void 0, sessionTokenInHeader);
1946
+ const { exchangeAppCheckToken } = getAuth(options);
1947
+ let appCheckTokenValue;
1948
+ try {
1949
+ const token = sessionTokenInHeader || "";
1950
+ const appCheckResult = await exchangeAppCheckToken(token);
1951
+ if (appCheckResult.data?.token) {
1952
+ appCheckTokenValue = appCheckResult.data.token;
1953
+ }
1954
+ } catch (error) {
1955
+ console.warn("App Check token exchange failed:", error);
1956
+ }
1957
+ const headers = new Headers();
1958
+ headers.set(
1959
+ constants.Headers.AppCheckToken,
1960
+ appCheckTokenValue || ""
1961
+ );
1962
+ const signedInRequestState = signedIn(context, data, headers, sessionTokenInHeader);
1619
1963
  return signedInRequestState;
1620
1964
  } catch (err) {
1621
1965
  return handleError(err, "header");
@@ -1629,6 +1973,16 @@ async function authenticateRequest(request, options) {
1629
1973
  if (isRequestForRefresh(err, context, request)) {
1630
1974
  const { data, error } = await handleRefresh();
1631
1975
  if (data) {
1976
+ const { exchangeAppCheckToken } = getAuth(options);
1977
+ let appCheckTokenValue;
1978
+ try {
1979
+ const appCheckResult = await exchangeAppCheckToken(data.token);
1980
+ if (appCheckResult.data?.token) {
1981
+ appCheckTokenValue = appCheckResult.data.token;
1982
+ }
1983
+ } catch (error2) {
1984
+ console.warn("App Check token exchange failed in error handler:", error2);
1985
+ }
1632
1986
  return signedIn(context, data.decoded, data.headers, data.token);
1633
1987
  }
1634
1988
  if (error?.cause?.reason) {