@frontmcp/auth 1.8.0 → 1.8.2

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/index.js CHANGED
@@ -269,9 +269,9 @@ __export(index_exports, {
269
269
  EagerCredentialLoader: () => EagerCredentialLoader,
270
270
  ElicitationSecretRequiredError: () => ElicitationSecretRequiredError,
271
271
  EncryptedRedisVault: () => EncryptedRedisVault,
272
- EncryptedStorageError: () => import_utils23.EncryptedStorageError,
272
+ EncryptedStorageError: () => import_utils24.EncryptedStorageError,
273
273
  EncryptedStorageSecureStoreBackend: () => EncryptedStorageSecureStoreBackend,
274
- EncryptedTypedStorage: () => import_utils23.EncryptedTypedStorage,
274
+ EncryptedTypedStorage: () => import_utils24.EncryptedTypedStorage,
275
275
  EncryptionContextNotSetError: () => EncryptionContextNotSetError,
276
276
  EncryptionKeyNotConfiguredError: () => EncryptionKeyNotConfiguredError,
277
277
  FetchCredentialMiddleware: () => FetchCredentialMiddleware,
@@ -319,7 +319,7 @@ __export(index_exports, {
319
319
  TokenVault: () => TokenVault,
320
320
  TransparentAuthorization: () => TransparentAuthorization,
321
321
  TransportIdGenerator: () => TransportIdGenerator,
322
- TypedStorage: () => import_utils22.TypedStorage,
322
+ TypedStorage: () => import_utils23.TypedStorage,
323
323
  VaultEncryption: () => VaultEncryption,
324
324
  VaultLoadError: () => VaultLoadError,
325
325
  VaultNotFoundError: () => VaultNotFoundError,
@@ -401,9 +401,9 @@ __export(index_exports, {
401
401
  credentialTypeSchema: () => credentialTypeSchema,
402
402
  customCredentialSchema: () => customCredentialSchema,
403
403
  decodeJwtPayloadSafe: () => decodeJwtPayloadSafe,
404
- decryptAesGcm: () => import_utils33.decryptAesGcm,
404
+ decryptAesGcm: () => import_utils34.decryptAesGcm,
405
405
  decryptSessionJson: () => decryptSessionJson,
406
- decryptValue: () => import_utils33.decryptValue,
406
+ decryptValue: () => import_utils34.decryptValue,
407
407
  defaultSessionRateLimiter: () => defaultSessionRateLimiter,
408
408
  deriveAuthorizationId: () => deriveAuthorizationId,
409
409
  deriveExpectedAudience: () => deriveExpectedAudience,
@@ -411,13 +411,13 @@ __export(index_exports, {
411
411
  deriveTypedUser: () => deriveTypedUser,
412
412
  detectAuthProviders: () => detectAuthProviders,
413
413
  detectedAuthProviderSchema: () => detectedAuthProviderSchema,
414
- encryptAesGcm: () => import_utils33.encryptAesGcm,
414
+ encryptAesGcm: () => import_utils34.encryptAesGcm,
415
415
  encryptJson: () => encryptJson,
416
- encryptValue: () => import_utils33.encryptValue,
416
+ encryptValue: () => import_utils34.encryptValue,
417
417
  encryptedBlobSchema: () => encryptedBlobSchema,
418
418
  encryptedDataSchema: () => encryptedDataSchema,
419
419
  encryptedVaultEntrySchema: () => encryptedVaultEntrySchema,
420
- escapeHtml: () => import_utils3.escapeHtml,
420
+ escapeHtml: () => import_utils4.escapeHtml,
421
421
  extraWideLayout: () => extraWideLayout,
422
422
  extractBearerToken: () => extractBearerToken,
423
423
  extractCacheHeaders: () => extractCacheHeaders,
@@ -439,8 +439,9 @@ __export(index_exports, {
439
439
  getTokenSignatureFingerprint: () => getTokenSignatureFingerprint,
440
440
  hasOnlyLocalhostRedirectUris: () => hasOnlyLocalhostRedirectUris,
441
441
  headerApplier: () => headerApplier,
442
- hkdfSha256: () => import_utils33.hkdfSha256,
442
+ hkdfSha256: () => import_utils34.hkdfSha256,
443
443
  incrementalAuthConfigSchema: () => incrementalAuthConfigSchema,
444
+ isAnonymousSubject: () => isAnonymousSubject,
444
445
  isCimdClientId: () => isCimdClientId,
445
446
  isFrontMcpCredentials: () => isFrontMcpCredentials,
446
447
  isJwt: () => isJwt,
@@ -453,7 +454,7 @@ __export(index_exports, {
453
454
  isRedisTokenStorage: () => isRedisTokenStorage,
454
455
  isRemoteMode: () => isRemoteMode,
455
456
  isSessionComplete: () => isSessionComplete,
456
- isSignedSession: () => import_utils15.isSignedData,
457
+ isSignedSession: () => import_utils16.isSignedData,
457
458
  isSoonExpiring: () => isSoonExpiring,
458
459
  isSoonExpiringProvider: () => isSoonExpiringProvider,
459
460
  isSqliteTokenStorage: () => isSqliteTokenStorage,
@@ -549,6 +550,9 @@ module.exports = __toCommonJS(index_exports);
549
550
 
550
551
  // libs/auth/src/jwks/jwks.service.ts
551
552
  var import_jose = require("jose");
553
+ var import_utils2 = require("@frontmcp/utils");
554
+
555
+ // libs/auth/src/cimd/cimd.validator.ts
552
556
  var import_utils = require("@frontmcp/utils");
553
557
 
554
558
  // libs/auth/src/cimd/cimd.errors.ts
@@ -814,122 +818,38 @@ function isIpAddress(hostname) {
814
818
  }
815
819
  return false;
816
820
  }
821
+ var BLOCKED_RANGE_REASONS = /* @__PURE__ */ new Map([
822
+ ["0.0.0.0/8", "Current network addresses (0.x.x.x) are not allowed"],
823
+ ["10.0.0.0/8", "Private IP addresses (10.x.x.x) are not allowed"],
824
+ ["100.64.0.0/10", "Carrier-grade NAT addresses (100.64-127.x.x) are not allowed"],
825
+ ["127.0.0.0/8", "Loopback addresses (127.x.x.x) are not allowed"],
826
+ ["169.254.0.0/16", "Link-local addresses (169.254.x.x) are not allowed"],
827
+ ["172.16.0.0/12", "Private IP addresses (172.16-31.x.x) are not allowed"],
828
+ ["192.0.0.0/24", "IETF protocol-assignment addresses (192.0.0.0/24) are not allowed"],
829
+ ["192.168.0.0/16", "Private IP addresses (192.168.x.x) are not allowed"],
830
+ ["224.0.0.0/4", "Multicast addresses are not allowed"],
831
+ ["255.255.255.255/32", "Broadcast address is not allowed"],
832
+ ["::/128", "IPv6 unspecified address (::) is not allowed"],
833
+ ["::1/128", "IPv6 loopback address (::1) is not allowed"],
834
+ ["fc00::/7", "IPv6 unique local addresses (fc00::/7) are not allowed"],
835
+ ["fe80::/10", "IPv6 link-local addresses (fe80::/10) are not allowed"]
836
+ ]);
817
837
  function checkIpAddress(ip) {
818
- const cleanIp = ip.replace(/^\[|\]$/g, "");
819
- if (cleanIp.includes(".") && !cleanIp.includes(":")) {
820
- return checkIpv4(cleanIp);
821
- }
822
- return checkIpv6(cleanIp);
823
- }
824
- function checkIpv4(ip) {
825
- const parts = ip.split(".").map(Number);
826
- if (parts.length !== 4 || parts.some((p) => isNaN(p) || p < 0 || p > 255)) {
827
- return { allowed: false, reason: "Invalid IPv4 address" };
828
- }
829
- const [a, b, c, d] = parts;
830
- if (a === 127) {
831
- return { allowed: false, reason: "Loopback addresses (127.x.x.x) are not allowed" };
832
- }
833
- if (a === 10) {
834
- return { allowed: false, reason: "Private IP addresses (10.x.x.x) are not allowed" };
835
- }
836
- if (a === 172 && b >= 16 && b <= 31) {
837
- return { allowed: false, reason: "Private IP addresses (172.16-31.x.x) are not allowed" };
838
- }
839
- if (a === 192 && b === 168) {
840
- return { allowed: false, reason: "Private IP addresses (192.168.x.x) are not allowed" };
841
- }
842
- if (a === 169 && b === 254) {
843
- return { allowed: false, reason: "Link-local addresses (169.254.x.x) are not allowed" };
844
- }
845
- if (a === 100 && b >= 64 && b <= 127) {
846
- return { allowed: false, reason: "Carrier-grade NAT addresses (100.64-127.x.x) are not allowed" };
847
- }
848
- if (a === 192 && b === 0 && c === 0) {
849
- return { allowed: false, reason: "IETF protocol-assignment addresses (192.0.0.0/24) are not allowed" };
850
- }
851
- if (a === 0) {
852
- return { allowed: false, reason: "Current network addresses (0.x.x.x) are not allowed" };
853
- }
854
- if (a === 255 && b === 255 && c === 255 && d === 255) {
855
- return { allowed: false, reason: "Broadcast address is not allowed" };
856
- }
857
- if (a >= 224 && a <= 239) {
858
- return { allowed: false, reason: "Multicast addresses are not allowed" };
859
- }
860
- return { allowed: true, reason: "" };
861
- }
862
- function expandIpv6(ip) {
863
- let text = ip.toLowerCase();
864
- if (text.includes("%")) {
865
- text = text.slice(0, text.indexOf("%"));
866
- }
867
- const dottedQuad = text.match(/^(.*:)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
868
- if (dottedQuad) {
869
- const octets = dottedQuad[2].split(".").map(Number);
870
- if (octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) return null;
871
- const high = (octets[0] << 8 | octets[1]).toString(16);
872
- const low = (octets[2] << 8 | octets[3]).toString(16);
873
- text = `${dottedQuad[1]}${high}:${low}`;
874
- }
875
- const halves = text.split("::");
876
- if (halves.length > 2) return null;
877
- const parseGroups = (part) => {
878
- if (part === "") return [];
879
- const groups = [];
880
- for (const group of part.split(":")) {
881
- if (!/^[0-9a-f]{1,4}$/.test(group)) return null;
882
- groups.push(parseInt(group, 16));
883
- }
884
- return groups;
885
- };
886
- const head = parseGroups(halves[0]);
887
- if (head === null) return null;
888
- if (halves.length === 1) {
889
- return head.length === 8 ? head : null;
890
- }
891
- const tail = parseGroups(halves[1]);
892
- if (tail === null) return null;
893
- if (head.length + tail.length > 7) return null;
894
- return [...head, ...new Array(8 - head.length - tail.length).fill(0), ...tail];
895
- }
896
- function checkIpv6(ip) {
897
- const groups = expandIpv6(ip);
898
- if (!groups) {
899
- return { allowed: false, reason: `Malformed IPv6 address: ${ip}` };
900
- }
901
- const isZeroPrefix = groups.slice(0, 7).every((group) => group === 0);
902
- if (isZeroPrefix && groups[7] === 1) {
903
- return { allowed: false, reason: "IPv6 loopback address (::1) is not allowed" };
904
- }
905
- if (isZeroPrefix && groups[7] === 0) {
906
- return { allowed: false, reason: "IPv6 unspecified address (::) is not allowed" };
907
- }
908
- if ((groups[0] & 65472) === 65152) {
909
- return { allowed: false, reason: "IPv6 link-local addresses (fe80::/10) are not allowed" };
910
- }
911
- if ((groups[0] & 65024) === 64512) {
912
- return { allowed: false, reason: "IPv6 unique local addresses (fc00::/7) are not allowed" };
838
+ const classification = (0, import_utils.classifyIpAddress)(ip);
839
+ if (!classification) {
840
+ const bareIp = ip.replace(/^\[|\]$/g, "");
841
+ return {
842
+ allowed: false,
843
+ reason: bareIp.includes(":") ? `Malformed IPv6 address: ${bareIp}` : "Invalid IPv4 address"
844
+ };
913
845
  }
914
- const embedded = extractEmbeddedIpv4(groups);
915
- if (embedded) {
916
- return checkIpv4(embedded);
846
+ if (classification.range === "public") {
847
+ return { allowed: true, reason: "" };
917
848
  }
918
- return { allowed: true, reason: "" };
919
- }
920
- function extractEmbeddedIpv4(groups) {
921
- const toDotted = () => {
922
- const high = groups[6];
923
- const low = groups[7];
924
- return `${high >> 8}.${high & 255}.${low >> 8}.${low & 255}`;
849
+ return {
850
+ allowed: false,
851
+ reason: BLOCKED_RANGE_REASONS.get(classification.cidr) ?? `Addresses in the ${classification.range} range (${classification.cidr}) are not allowed`
925
852
  };
926
- const firstFive = groups.slice(0, 5).every((group) => group === 0);
927
- if (firstFive && groups[5] === 65535) return toDotted();
928
- if (firstFive && groups[5] === 0) return toDotted();
929
- if (groups[0] === 100 && groups[1] === 65435 && groups.slice(2, 6).every((group) => group === 0)) {
930
- return toDotted();
931
- }
932
- return null;
933
853
  }
934
854
  function isDomainInList(hostname, domainList) {
935
855
  const lowerHostname = hostname.toLowerCase();
@@ -1060,9 +980,9 @@ var JwksService = class {
1060
980
  * Returns null if persistence is disabled (production).
1061
981
  */
1062
982
  async getKeyPersistence() {
1063
- if ((0, import_utils.isProduction)()) return null;
983
+ if ((0, import_utils2.isProduction)()) return null;
1064
984
  if (!this.keyPersistence) {
1065
- this.keyPersistence = await (0, import_utils.createKeyPersistence)({
985
+ this.keyPersistence = await (0, import_utils2.createKeyPersistence)({
1066
986
  baseDir: ".frontmcp/keys"
1067
987
  });
1068
988
  }
@@ -1181,7 +1101,7 @@ var JwksService = class {
1181
1101
  if (!jwtAlg) {
1182
1102
  return { ok: false, error: "missing_alg" };
1183
1103
  }
1184
- const isValid = await (0, import_utils.rsaVerify)(
1104
+ const isValid = await (0, import_utils2.rsaVerify)(
1185
1105
  jwtAlg,
1186
1106
  Buffer.from(signatureInput),
1187
1107
  matchingKey,
@@ -1324,10 +1244,10 @@ var JwksService = class {
1324
1244
  const parsed = new URL(currentUrl);
1325
1245
  const host = parsed.hostname.toLowerCase();
1326
1246
  const isLocalhost = host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
1327
- if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && (isLocalhost || !(0, import_utils.isProduction)()))) {
1247
+ if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && (isLocalhost || !(0, import_utils2.isProduction)()))) {
1328
1248
  throw new Error(`insecure scheme "${parsed.protocol}"`);
1329
1249
  }
1330
- if (!(isLocalhost && !(0, import_utils.isProduction)())) {
1250
+ if (!(isLocalhost && !(0, import_utils2.isProduction)())) {
1331
1251
  const ssrf = await resolveAndCheckHostname(parsed.hostname);
1332
1252
  if (!ssrf.allowed) throw new Error(`blocked host: ${ssrf.reason}`);
1333
1253
  }
@@ -1338,11 +1258,10 @@ var JwksService = class {
1338
1258
  // Follow redirects manually so each hop is re-validated (scheme + SSRF).
1339
1259
  redirect: "manual"
1340
1260
  });
1341
- if (res.status >= 300 && res.status < 400) {
1261
+ if ((0, import_utils2.isRedirectResponse)(res)) {
1342
1262
  const location = res.headers.get("location");
1343
- if (!location || hop >= MAX_JWKS_FETCH_HOPS) {
1344
- throw new Error("too many redirects");
1345
- }
1263
+ if (!location) throw new Error("redirect without a readable Location header");
1264
+ if (hop >= MAX_JWKS_FETCH_HOPS) throw new Error("too many redirects");
1346
1265
  currentUrl = new URL(location, currentUrl).toString();
1347
1266
  continue;
1348
1267
  }
@@ -1435,13 +1354,13 @@ var JwksService = class {
1435
1354
  const { generateKeyPairSync } = require("node:crypto");
1436
1355
  if (alg === "RS256") {
1437
1356
  const { privateKey, publicKey } = generateKeyPairSync("rsa", { modulusLength: 2048 });
1438
- const kid = (0, import_utils.bytesToHex)((0, import_utils.randomBytes)(8));
1357
+ const kid = (0, import_utils2.bytesToHex)((0, import_utils2.randomBytes)(8));
1439
1358
  const publicJwk = publicKey.export({ format: "jwk" });
1440
1359
  Object.assign(publicJwk, { kid, alg: "RS256", use: "sig", kty: "RSA" });
1441
1360
  return { kid, privateKey, publicJwk: { keys: [publicJwk] }, createdAt: Date.now() };
1442
1361
  } else {
1443
1362
  const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
1444
- const kid = (0, import_utils.bytesToHex)((0, import_utils.randomBytes)(8));
1363
+ const kid = (0, import_utils2.bytesToHex)((0, import_utils2.randomBytes)(8));
1445
1364
  const publicJwk = publicKey.export({ format: "jwk" });
1446
1365
  Object.assign(publicJwk, { kid, alg: "ES256", use: "sig", kty: "EC" });
1447
1366
  return { kid, privateKey, publicJwk: { keys: [publicJwk] }, createdAt: Date.now() };
@@ -1450,8 +1369,8 @@ var JwksService = class {
1450
1369
  };
1451
1370
 
1452
1371
  // libs/auth/src/ui/base-layout.ts
1453
- var import_utils2 = require("@frontmcp/utils");
1454
1372
  var import_utils3 = require("@frontmcp/utils");
1373
+ var import_utils4 = require("@frontmcp/utils");
1455
1374
  var CDN = {
1456
1375
  /** Tailwind CSS v4 Browser CDN - generates styles on-the-fly with @theme support */
1457
1376
  tailwind: "https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4",
@@ -1530,13 +1449,13 @@ function baseLayout(content, options) {
1530
1449
  }
1531
1450
  ${customCss}
1532
1451
  </style>` : "";
1533
- const metaDescription = description ? `<meta name="description" content="${(0, import_utils2.escapeHtml)(description)}">` : "";
1452
+ const metaDescription = description ? `<meta name="description" content="${(0, import_utils3.escapeHtml)(description)}">` : "";
1534
1453
  return `<!DOCTYPE html>
1535
1454
  <html lang="en">
1536
1455
  <head>
1537
1456
  <meta charset="UTF-8">
1538
1457
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1539
- <title>${(0, import_utils2.escapeHtml)(title)} - FrontMCP</title>
1458
+ <title>${(0, import_utils3.escapeHtml)(title)} - FrontMCP</title>
1540
1459
  ${metaDescription}
1541
1460
 
1542
1461
  <!-- Google Fonts CDN - Inter (modern UI font) -->
@@ -1547,7 +1466,7 @@ function baseLayout(content, options) {
1547
1466
  ${tailwindBlock}
1548
1467
  ${headExtra}
1549
1468
  </head>
1550
- <body class="${(0, import_utils2.escapeHtml)(bodyClass)}">
1469
+ <body class="${(0, import_utils3.escapeHtml)(bodyClass)}">
1551
1470
  ${content}
1552
1471
  </body>
1553
1472
  </html>`;
@@ -1602,7 +1521,7 @@ function extraWideLayout(content, options) {
1602
1521
  }
1603
1522
 
1604
1523
  // libs/auth/src/ui/templates.ts
1605
- var escapeHtml3 = import_utils3.escapeHtml;
1524
+ var escapeHtml3 = import_utils4.escapeHtml;
1606
1525
  function buildConsentPage(params) {
1607
1526
  const { apps, clientName, pendingAuthId, csrfToken, callbackPath } = params;
1608
1527
  const appCards = apps.map((app) => buildAppCardHtml(app, pendingAuthId, csrfToken, callbackPath)).join("\n");
@@ -2104,7 +2023,7 @@ function renderLocalLoginPage(login, ctx, values) {
2104
2023
 
2105
2024
  // libs/auth/src/session/authorization.store.ts
2106
2025
  var import_lazy_zod = require("@frontmcp/lazy-zod");
2107
- var import_utils4 = require("@frontmcp/utils");
2026
+ var import_utils5 = require("@frontmcp/utils");
2108
2027
  var pkceChallengeSchema = import_lazy_zod.z.object({
2109
2028
  challenge: import_lazy_zod.z.string().min(43).max(128),
2110
2029
  method: import_lazy_zod.z.literal("S256")
@@ -2139,10 +2058,10 @@ var AUTH_CODE_TTL_MS = 60 * 1e3;
2139
2058
  var PENDING_AUTH_TTL_MS = 10 * 60 * 1e3;
2140
2059
  var REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
2141
2060
  function generateAuthorizationCode() {
2142
- return (0, import_utils4.randomUUID)().replace(/-/g, "") + (0, import_utils4.randomUUID)().replace(/-/g, "");
2061
+ return (0, import_utils5.randomUUID)().replace(/-/g, "") + (0, import_utils5.randomUUID)().replace(/-/g, "");
2143
2062
  }
2144
2063
  function generateRefreshTokenValue() {
2145
- return (0, import_utils4.randomUUID)() + "-" + (0, import_utils4.randomUUID)();
2064
+ return (0, import_utils5.randomUUID)() + "-" + (0, import_utils5.randomUUID)();
2146
2065
  }
2147
2066
  function buildCodeRecord(params) {
2148
2067
  const now = Date.now();
@@ -2173,7 +2092,7 @@ function buildCodeRecord(params) {
2173
2092
  function buildPendingRecord(params) {
2174
2093
  const now = Date.now();
2175
2094
  return {
2176
- id: (0, import_utils4.randomUUID)(),
2095
+ id: (0, import_utils5.randomUUID)(),
2177
2096
  clientId: params.clientId,
2178
2097
  redirectUri: params.redirectUri,
2179
2098
  scopes: params.scopes,
@@ -2222,11 +2141,11 @@ function verifyPkce(codeVerifier, challenge) {
2222
2141
  if (challenge.method !== "S256") {
2223
2142
  return false;
2224
2143
  }
2225
- const hash = (0, import_utils4.sha256Base64url)(codeVerifier);
2144
+ const hash = (0, import_utils5.sha256Base64url)(codeVerifier);
2226
2145
  return hash === challenge.challenge;
2227
2146
  }
2228
2147
  function generatePkceChallenge(codeVerifier) {
2229
- const challenge = (0, import_utils4.sha256Base64url)(codeVerifier);
2148
+ const challenge = (0, import_utils5.sha256Base64url)(codeVerifier);
2230
2149
  return { challenge, method: "S256" };
2231
2150
  }
2232
2151
  var InMemoryAuthorizationStore = class {
@@ -2422,7 +2341,7 @@ var RedisAuthorizationStore = class {
2422
2341
  };
2423
2342
 
2424
2343
  // libs/auth/src/session/storage-authorization.store.ts
2425
- var import_utils5 = require("@frontmcp/utils");
2344
+ var import_utils6 = require("@frontmcp/utils");
2426
2345
  var StorageAuthorizationStore = class {
2427
2346
  codeStore;
2428
2347
  pendingStore;
@@ -2433,9 +2352,9 @@ var StorageAuthorizationStore = class {
2433
2352
  this.namespace = options.namespace ?? "oauth";
2434
2353
  this.storageIsNamespaced = this.isNamespacedStorage(storage);
2435
2354
  const base = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
2436
- this.codeStore = new import_utils5.TypedStorage(base);
2437
- this.pendingStore = new import_utils5.TypedStorage(base);
2438
- this.refreshStore = new import_utils5.TypedStorage(base);
2355
+ this.codeStore = new import_utils6.TypedStorage(base);
2356
+ this.pendingStore = new import_utils6.TypedStorage(base);
2357
+ this.refreshStore = new import_utils6.TypedStorage(base);
2439
2358
  }
2440
2359
  // ============================================
2441
2360
  // Record builders (pure; shared with in-memory store)
@@ -2808,11 +2727,11 @@ var authorizationVaultEntrySchema = import_lazy_zod2.z.object({
2808
2727
  });
2809
2728
 
2810
2729
  // libs/auth/src/session/session-credential-vault.ts
2811
- var import_utils7 = require("@frontmcp/utils");
2730
+ var import_utils8 = require("@frontmcp/utils");
2812
2731
 
2813
2732
  // libs/auth/src/session/vault-encryption.ts
2814
2733
  var import_lazy_zod3 = require("@frontmcp/lazy-zod");
2815
- var import_utils6 = require("@frontmcp/utils");
2734
+ var import_utils7 = require("@frontmcp/utils");
2816
2735
  var encryptedDataSchema = import_lazy_zod3.z.object({
2817
2736
  /** Version for future algorithm changes */
2818
2737
  v: import_lazy_zod3.z.literal(1),
@@ -2852,7 +2771,7 @@ var VaultEncryption = class {
2852
2771
  ];
2853
2772
  const ikm = new TextEncoder().encode(ikmParts.join(""));
2854
2773
  const infoBytes = new TextEncoder().encode(this.hkdfInfo);
2855
- const key = await (0, import_utils6.hkdfSha256)(ikm, new Uint8Array(0), infoBytes, 32);
2774
+ const key = await (0, import_utils7.hkdfSha256)(ikm, new Uint8Array(0), infoBytes, 32);
2856
2775
  return key;
2857
2776
  }
2858
2777
  /**
@@ -2879,7 +2798,7 @@ var VaultEncryption = class {
2879
2798
  ];
2880
2799
  const ikm = new TextEncoder().encode(ikmParts.join(""));
2881
2800
  const infoBytes = new TextEncoder().encode(this.hkdfInfo);
2882
- const key = await (0, import_utils6.hkdfSha256)(ikm, new Uint8Array(0), infoBytes, 32);
2801
+ const key = await (0, import_utils7.hkdfSha256)(ikm, new Uint8Array(0), infoBytes, 32);
2883
2802
  return key;
2884
2803
  }
2885
2804
  /**
@@ -2893,14 +2812,14 @@ var VaultEncryption = class {
2893
2812
  if (key.length !== 32) {
2894
2813
  throw new Error("Encryption key must be 32 bytes");
2895
2814
  }
2896
- const iv = (0, import_utils6.randomBytes)(12);
2897
- const { ciphertext, tag } = await (0, import_utils6.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
2815
+ const iv = (0, import_utils7.randomBytes)(12);
2816
+ const { ciphertext, tag } = await (0, import_utils7.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
2898
2817
  return {
2899
2818
  v: 1,
2900
2819
  alg: "aes-256-gcm",
2901
- iv: (0, import_utils6.base64urlEncode)(iv),
2902
- ct: (0, import_utils6.base64urlEncode)(ciphertext),
2903
- tag: (0, import_utils6.base64urlEncode)(tag)
2820
+ iv: (0, import_utils7.base64urlEncode)(iv),
2821
+ ct: (0, import_utils7.base64urlEncode)(ciphertext),
2822
+ tag: (0, import_utils7.base64urlEncode)(tag)
2904
2823
  };
2905
2824
  }
2906
2825
  /**
@@ -2920,11 +2839,11 @@ var VaultEncryption = class {
2920
2839
  throw new Error("Invalid encrypted data format");
2921
2840
  }
2922
2841
  const { iv, ct, tag } = parsed.data;
2923
- const ivBuffer = (0, import_utils6.base64urlDecode)(iv);
2924
- const ciphertext = (0, import_utils6.base64urlDecode)(ct);
2925
- const tagBuffer = (0, import_utils6.base64urlDecode)(tag);
2842
+ const ivBuffer = (0, import_utils7.base64urlDecode)(iv);
2843
+ const ciphertext = (0, import_utils7.base64urlDecode)(ct);
2844
+ const tagBuffer = (0, import_utils7.base64urlDecode)(tag);
2926
2845
  try {
2927
- const plaintext = await (0, import_utils6.decryptAesGcm)(key, ciphertext, ivBuffer, tagBuffer);
2846
+ const plaintext = await (0, import_utils7.decryptAesGcm)(key, ciphertext, ivBuffer, tagBuffer);
2928
2847
  return new TextDecoder().decode(plaintext);
2929
2848
  } catch (_error) {
2930
2849
  throw new Error("Decryption failed: invalid key or corrupted data");
@@ -3064,7 +2983,7 @@ var SessionCredentialVault = class {
3064
2983
  * it expires via TTL when configured.
3065
2984
  */
3066
2985
  async rotateVault(sub) {
3067
- const vaultId = (0, import_utils7.randomUUID)();
2986
+ const vaultId = (0, import_utils8.randomUUID)();
3068
2987
  await this.storage.set(this.indexKey(sub), vaultId, this.credentialSetOpts);
3069
2988
  return vaultId;
3070
2989
  }
@@ -3213,19 +3132,19 @@ var SessionCredentialVault = class {
3213
3132
  }
3214
3133
  };
3215
3134
  function resolveVaultPepper(logger) {
3216
- const fromEnv = (0, import_utils7.getEnv)("VAULT_SECRET") ?? (0, import_utils7.getEnv)("JWT_SECRET");
3135
+ const fromEnv = (0, import_utils8.getEnv)("VAULT_SECRET") ?? (0, import_utils8.getEnv)("JWT_SECRET");
3217
3136
  if (fromEnv && fromEnv.trim().length > 0) return fromEnv;
3218
3137
  logger.warn(
3219
3138
  "SessionCredentialVault: neither VAULT_SECRET nor JWT_SECRET is set; using a random per-process pepper. Stored credentials will NOT survive a restart and cannot be shared across instances. Set VAULT_SECRET (or JWT_SECRET) for persistent, multi-instance credential storage."
3220
3139
  );
3221
- return (0, import_utils7.randomUUID)() + (0, import_utils7.randomUUID)();
3140
+ return (0, import_utils8.randomUUID)() + (0, import_utils8.randomUUID)();
3222
3141
  }
3223
3142
  function errMsg(err) {
3224
3143
  return err instanceof Error ? err.message : String(err);
3225
3144
  }
3226
3145
 
3227
3146
  // libs/auth/src/session/token-storage.factory.ts
3228
- var import_utils8 = require("@frontmcp/utils");
3147
+ var import_utils9 = require("@frontmcp/utils");
3229
3148
  function isRedisTokenStorage(config) {
3230
3149
  return typeof config === "object" && config !== null && "redis" in config && !!config.redis;
3231
3150
  }
@@ -3237,7 +3156,7 @@ function isPersistentTokenStorage(config) {
3237
3156
  }
3238
3157
  async function createTokenStorageAdapter(config) {
3239
3158
  if (config === void 0 || config === "memory") {
3240
- const adapter = new import_utils8.MemoryStorageAdapter();
3159
+ const adapter = new import_utils9.MemoryStorageAdapter();
3241
3160
  await adapter.connect();
3242
3161
  return adapter;
3243
3162
  }
@@ -3254,14 +3173,14 @@ async function createTokenStorageAdapter(config) {
3254
3173
  }
3255
3174
  if (isRedisTokenStorage(config)) {
3256
3175
  const { host, port, password, db, tls, keyPrefix } = config.redis;
3257
- const adapter = new import_utils8.RedisStorageAdapter({
3176
+ const adapter = new import_utils9.RedisStorageAdapter({
3258
3177
  config: { host, port, password, db, tls },
3259
3178
  keyPrefix: keyPrefix ?? ""
3260
3179
  });
3261
3180
  await adapter.connect();
3262
3181
  return adapter;
3263
3182
  }
3264
- const fallback = new import_utils8.MemoryStorageAdapter();
3183
+ const fallback = new import_utils9.MemoryStorageAdapter();
3265
3184
  await fallback.connect();
3266
3185
  return fallback;
3267
3186
  }
@@ -3281,7 +3200,7 @@ async function createSessionCredentialVault(options) {
3281
3200
  }
3282
3201
 
3283
3202
  // libs/auth/src/session/credential-resume-link.ts
3284
- var import_utils9 = require("@frontmcp/utils");
3203
+ var import_utils10 = require("@frontmcp/utils");
3285
3204
  var DEFAULT_RESUME_TTL_MS = 6e5;
3286
3205
  function signCredentialResumeToken(input, secret) {
3287
3206
  const payload = {
@@ -3290,7 +3209,7 @@ function signCredentialResumeToken(input, secret) {
3290
3209
  ...input.context !== void 0 ? { context: input.context } : {},
3291
3210
  exp: Date.now() + (input.ttlMs ?? DEFAULT_RESUME_TTL_MS)
3292
3211
  };
3293
- const signedJson = (0, import_utils9.signData)(payload, { secret });
3212
+ const signedJson = (0, import_utils10.signData)(payload, { secret });
3294
3213
  return Buffer.from(signedJson, "utf8").toString("base64url");
3295
3214
  }
3296
3215
  function verifyCredentialResumeToken(token, secret, now = Date.now()) {
@@ -3300,7 +3219,7 @@ function verifyCredentialResumeToken(token, secret, now = Date.now()) {
3300
3219
  } catch {
3301
3220
  return null;
3302
3221
  }
3303
- const payload = (0, import_utils9.verifyData)(signedJson, { secret });
3222
+ const payload = (0, import_utils10.verifyData)(signedJson, { secret });
3304
3223
  if (!payload) return null;
3305
3224
  if (typeof payload.sub !== "string" || typeof payload.key !== "string" || !Number.isFinite(payload.exp)) {
3306
3225
  return null;
@@ -3319,7 +3238,7 @@ function buildCredentialResumeUrl(basePath, token) {
3319
3238
  }
3320
3239
 
3321
3240
  // libs/auth/src/session/incremental-auth-ticket.ts
3322
- var import_utils10 = require("@frontmcp/utils");
3241
+ var import_utils11 = require("@frontmcp/utils");
3323
3242
  var DEFAULT_INCREMENTAL_TICKET_TTL_MS = 3e5;
3324
3243
  function signIncrementalAuthTicket(input, secret) {
3325
3244
  const payload = {
@@ -3327,10 +3246,10 @@ function signIncrementalAuthTicket(input, secret) {
3327
3246
  appId: input.appId,
3328
3247
  ...input.toolId !== void 0 ? { toolId: input.toolId } : {},
3329
3248
  ...input.priorAppIds !== void 0 ? { priorAppIds: input.priorAppIds } : {},
3330
- jti: (0, import_utils10.randomUUID)(),
3249
+ jti: (0, import_utils11.randomUUID)(),
3331
3250
  exp: Date.now() + (input.ttlMs ?? DEFAULT_INCREMENTAL_TICKET_TTL_MS)
3332
3251
  };
3333
- const signedJson = (0, import_utils10.signData)(payload, { secret });
3252
+ const signedJson = (0, import_utils11.signData)(payload, { secret });
3334
3253
  return Buffer.from(signedJson, "utf8").toString("base64url");
3335
3254
  }
3336
3255
  function verifyIncrementalAuthTicket(token, secret, now = Date.now()) {
@@ -3340,7 +3259,7 @@ function verifyIncrementalAuthTicket(token, secret, now = Date.now()) {
3340
3259
  } catch {
3341
3260
  return null;
3342
3261
  }
3343
- const payload = (0, import_utils10.verifyData)(signedJson, { secret });
3262
+ const payload = (0, import_utils11.verifyData)(signedJson, { secret });
3344
3263
  if (!payload) return null;
3345
3264
  if (typeof payload.sub !== "string" || payload.sub.length === 0) return null;
3346
3265
  if (typeof payload.appId !== "string" || payload.appId.length === 0) return null;
@@ -3520,7 +3439,7 @@ function errMsg2(err) {
3520
3439
  var SECURE_STORE_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:SECURE_STORE_ACCESSOR");
3521
3440
 
3522
3441
  // libs/auth/src/session/secure-store-accessor.impl.ts
3523
- var import_utils11 = require("@frontmcp/utils");
3442
+ var import_utils12 = require("@frontmcp/utils");
3524
3443
  var GLOBAL_NAMESPACE = "global";
3525
3444
  var SecureStoreAccessorImpl = class {
3526
3445
  backend;
@@ -3549,12 +3468,12 @@ var SecureStoreAccessorImpl = class {
3549
3468
  return GLOBAL_NAMESPACE;
3550
3469
  case "session": {
3551
3470
  const sid = this.resolveSessionId();
3552
- return sid ? `s:${(0, import_utils11.sha256Hex)(sid).slice(0, 32)}` : void 0;
3471
+ return sid ? `s:${(0, import_utils12.sha256Hex)(sid).slice(0, 32)}` : void 0;
3553
3472
  }
3554
3473
  case "user":
3555
3474
  default: {
3556
3475
  const sub = this.resolveSub();
3557
- return sub ? `u:${(0, import_utils11.sha256Hex)(sub).slice(0, 32)}` : void 0;
3476
+ return sub ? `u:${(0, import_utils12.sha256Hex)(sub).slice(0, 32)}` : void 0;
3558
3477
  }
3559
3478
  }
3560
3479
  }
@@ -3595,7 +3514,7 @@ function errMsg3(err) {
3595
3514
  }
3596
3515
 
3597
3516
  // libs/auth/src/session/secure-store.factory.ts
3598
- var import_utils12 = require("@frontmcp/utils");
3517
+ var import_utils13 = require("@frontmcp/utils");
3599
3518
  function isCustomBackendConfig(config) {
3600
3519
  return typeof config === "object" && config !== null && "backend" in config && !!config.backend;
3601
3520
  }
@@ -3644,7 +3563,7 @@ async function createSecureStore(options) {
3644
3563
  if (storage) {
3645
3564
  adapter = storage;
3646
3565
  } else if (kind === "memory") {
3647
- adapter = new import_utils12.MemoryStorageAdapter();
3566
+ adapter = new import_utils13.MemoryStorageAdapter();
3648
3567
  await adapter.connect();
3649
3568
  } else {
3650
3569
  adapter = await createTokenStorageAdapter(toTokenStorageConfig(config));
@@ -3658,7 +3577,7 @@ async function createSecureStore(options) {
3658
3577
  }
3659
3578
 
3660
3579
  // libs/auth/src/session/token.vault.ts
3661
- var import_utils13 = require("@frontmcp/utils");
3580
+ var import_utils14 = require("@frontmcp/utils");
3662
3581
  var TokenVault = class {
3663
3582
  /** Active key used for new encryptions */
3664
3583
  active;
@@ -3687,14 +3606,14 @@ var TokenVault = class {
3687
3606
  this.keys.set(k.kid, k.key);
3688
3607
  }
3689
3608
  async encrypt(plaintext, opts) {
3690
- const iv = (0, import_utils13.randomBytes)(12);
3691
- const { ciphertext, tag } = await (0, import_utils13.encryptAesGcm)(this.active.key, new TextEncoder().encode(plaintext), iv);
3609
+ const iv = (0, import_utils14.randomBytes)(12);
3610
+ const { ciphertext, tag } = await (0, import_utils14.encryptAesGcm)(this.active.key, new TextEncoder().encode(plaintext), iv);
3692
3611
  return {
3693
3612
  alg: "A256GCM",
3694
3613
  kid: this.active.kid,
3695
- iv: (0, import_utils13.base64urlEncode)(iv),
3696
- tag: (0, import_utils13.base64urlEncode)(tag),
3697
- data: (0, import_utils13.base64urlEncode)(ciphertext),
3614
+ iv: (0, import_utils14.base64urlEncode)(iv),
3615
+ tag: (0, import_utils14.base64urlEncode)(tag),
3616
+ data: (0, import_utils14.base64urlEncode)(ciphertext),
3698
3617
  exp: opts?.exp,
3699
3618
  meta: opts?.meta
3700
3619
  };
@@ -3708,16 +3627,16 @@ var TokenVault = class {
3708
3627
  }
3709
3628
  const key = this.keys.get(blob.kid);
3710
3629
  if (!key) throw new Error(`vault_unknown_kid:${blob.kid}`);
3711
- const iv = (0, import_utils13.base64urlDecode)(blob.iv);
3712
- const tag = (0, import_utils13.base64urlDecode)(blob.tag);
3713
- const data = (0, import_utils13.base64urlDecode)(blob.data);
3714
- const plaintext = await (0, import_utils13.decryptAesGcm)(key, data, iv, tag);
3630
+ const iv = (0, import_utils14.base64urlDecode)(blob.iv);
3631
+ const tag = (0, import_utils14.base64urlDecode)(blob.tag);
3632
+ const data = (0, import_utils14.base64urlDecode)(blob.data);
3633
+ const plaintext = await (0, import_utils14.decryptAesGcm)(key, data, iv, tag);
3715
3634
  return new TextDecoder().decode(plaintext);
3716
3635
  }
3717
3636
  };
3718
3637
 
3719
3638
  // libs/auth/src/session/index.ts
3720
- var import_utils33 = require("@frontmcp/utils");
3639
+ var import_utils34 = require("@frontmcp/utils");
3721
3640
 
3722
3641
  // libs/auth/src/session/transport-session.types.ts
3723
3642
  var import_lazy_zod4 = require("@frontmcp/lazy-zod");
@@ -3813,10 +3732,10 @@ var redisConfigSchema = import_lazy_zod4.z.object({
3813
3732
  });
3814
3733
 
3815
3734
  // libs/auth/src/session/session-crypto.ts
3816
- var import_utils15 = require("@frontmcp/utils");
3735
+ var import_utils16 = require("@frontmcp/utils");
3817
3736
 
3818
3737
  // libs/auth/src/errors/auth-internal.error.ts
3819
- var import_utils14 = require("@frontmcp/utils");
3738
+ var import_utils15 = require("@frontmcp/utils");
3820
3739
  var AuthInternalError = class extends Error {
3821
3740
  /**
3822
3741
  * Unique error ID for tracking in logs.
@@ -3838,7 +3757,7 @@ var AuthInternalError = class extends Error {
3838
3757
  super(message);
3839
3758
  this.name = this.constructor.name;
3840
3759
  this.code = code;
3841
- this.errorId = `err_${(0, import_utils14.bytesToHex)((0, import_utils14.randomBytes)(8))}`;
3760
+ this.errorId = `err_${(0, import_utils15.bytesToHex)((0, import_utils15.randomBytes)(8))}`;
3842
3761
  Error.captureStackTrace(this, this.constructor);
3843
3762
  }
3844
3763
  /**
@@ -3977,9 +3896,9 @@ var AuthFlowError = class extends AuthInternalError {
3977
3896
 
3978
3897
  // libs/auth/src/session/session-crypto.ts
3979
3898
  function getSigningSecret(config) {
3980
- const secret = config?.secret || (0, import_utils15.getEnv)("MCP_SESSION_SECRET");
3899
+ const secret = config?.secret || (0, import_utils16.getEnv)("MCP_SESSION_SECRET");
3981
3900
  if (!secret) {
3982
- if ((0, import_utils15.isProduction)()) {
3901
+ if ((0, import_utils16.isProduction)()) {
3983
3902
  throw new SessionSecretRequiredError("session signing");
3984
3903
  }
3985
3904
  console.warn("[SessionCrypto] MCP_SESSION_SECRET not set. Using insecure default for development only.");
@@ -3991,13 +3910,13 @@ function resolveConfig(config) {
3991
3910
  return { secret: getSigningSecret(config) };
3992
3911
  }
3993
3912
  function signSession(session, config) {
3994
- return (0, import_utils15.signData)(session, resolveConfig(config));
3913
+ return (0, import_utils16.signData)(session, resolveConfig(config));
3995
3914
  }
3996
3915
  function verifySession(signedData, config) {
3997
- return (0, import_utils15.verifyData)(signedData, resolveConfig(config));
3916
+ return (0, import_utils16.verifyData)(signedData, resolveConfig(config));
3998
3917
  }
3999
3918
  function verifyOrParseSession(data, config) {
4000
- return (0, import_utils15.verifyOrParseData)(data, resolveConfig(config));
3919
+ return (0, import_utils16.verifyOrParseData)(data, resolveConfig(config));
4001
3920
  }
4002
3921
 
4003
3922
  // libs/auth/src/session/session-rate-limiter.ts
@@ -4124,7 +4043,7 @@ var SessionRateLimiter = class {
4124
4043
  var defaultSessionRateLimiter = new SessionRateLimiter();
4125
4044
 
4126
4045
  // libs/auth/src/session/session.transport.ts
4127
- var import_utils16 = require("@frontmcp/utils");
4046
+ var import_utils17 = require("@frontmcp/utils");
4128
4047
  var TransportIdGenerator = class {
4129
4048
  /**
4130
4049
  * Create a transport session ID.
@@ -4133,7 +4052,7 @@ var TransportIdGenerator = class {
4133
4052
  * @returns A transport session ID (UUID without dashes)
4134
4053
  */
4135
4054
  static createId() {
4136
- return (0, import_utils16.randomUUID)().replace(/-/g, "");
4055
+ return (0, import_utils17.randomUUID)().replace(/-/g, "");
4137
4056
  }
4138
4057
  };
4139
4058
 
@@ -4182,7 +4101,7 @@ var TinyTtlCache = class {
4182
4101
  };
4183
4102
 
4184
4103
  // libs/auth/src/session/utils/auth-token.utils.ts
4185
- var import_utils17 = require("@frontmcp/utils");
4104
+ var import_utils18 = require("@frontmcp/utils");
4186
4105
  function isJwt(token) {
4187
4106
  if (!token) return false;
4188
4107
  return token.split(".").length === 3;
@@ -4192,7 +4111,7 @@ function getTokenSignatureFingerprint(token) {
4192
4111
  const sig = token.split(".")[2];
4193
4112
  if (sig) return sig;
4194
4113
  }
4195
- return (0, import_utils17.sha256Base64url)(token);
4114
+ return (0, import_utils18.sha256Base64url)(token);
4196
4115
  }
4197
4116
  function extractClaimValue(claims, key, validator) {
4198
4117
  const value = claims[key];
@@ -4224,26 +4143,26 @@ function extractBearerToken(header) {
4224
4143
  }
4225
4144
 
4226
4145
  // libs/auth/src/session/utils/session-crypto.utils.ts
4227
- var import_utils18 = require("@frontmcp/utils");
4146
+ var import_utils19 = require("@frontmcp/utils");
4228
4147
  var cachedKey = null;
4229
4148
  function getKey() {
4230
4149
  if (cachedKey) return cachedKey;
4231
- const secret = (0, import_utils18.getEnv)("MCP_SESSION_SECRET");
4150
+ const secret = (0, import_utils19.getEnv)("MCP_SESSION_SECRET");
4232
4151
  if (!secret) {
4233
- if ((0, import_utils18.isProduction)()) {
4152
+ if ((0, import_utils19.isProduction)()) {
4234
4153
  throw new SessionSecretRequiredError("session ID encryption");
4235
4154
  }
4236
4155
  console.warn(
4237
4156
  "[SessionIdUtils] Using machine ID as session encryption secret - NOT SECURE FOR PRODUCTION. Set MCP_SESSION_SECRET environment variable for secure session encryption."
4238
4157
  );
4239
4158
  }
4240
- const base = secret || (0, import_utils18.getMachineId)();
4241
- cachedKey = (0, import_utils18.sha256)(new TextEncoder().encode(base));
4159
+ const base = secret || (0, import_utils19.getMachineId)();
4160
+ cachedKey = (0, import_utils19.sha256)(new TextEncoder().encode(base));
4242
4161
  return cachedKey;
4243
4162
  }
4244
4163
  function encryptJson(obj) {
4245
4164
  const key = getKey();
4246
- const encrypted = (0, import_utils18.encryptValue)(obj, key);
4165
+ const encrypted = (0, import_utils19.encryptValue)(obj, key);
4247
4166
  return `${encrypted.iv}.${encrypted.tag}.${encrypted.data}`;
4248
4167
  }
4249
4168
  function decryptSessionJson(sessionId) {
@@ -4252,7 +4171,7 @@ function decryptSessionJson(sessionId) {
4252
4171
  const [ivB64, tagB64, ctB64] = parts;
4253
4172
  if (!ivB64 || !tagB64 || !ctB64) return null;
4254
4173
  const key = getKey();
4255
- return (0, import_utils18.decryptValue)({ alg: "A256GCM", iv: ivB64, tag: tagB64, data: ctB64 }, key);
4174
+ return (0, import_utils19.decryptValue)({ alg: "A256GCM", iv: ivB64, tag: tagB64, data: ctB64 }, key);
4256
4175
  }
4257
4176
  function safeDecrypt(sessionId) {
4258
4177
  try {
@@ -4266,11 +4185,11 @@ function resetCachedKey() {
4266
4185
  }
4267
4186
 
4268
4187
  // libs/auth/src/session/storage/index.ts
4269
- var import_utils22 = require("@frontmcp/utils");
4270
4188
  var import_utils23 = require("@frontmcp/utils");
4189
+ var import_utils24 = require("@frontmcp/utils");
4271
4190
 
4272
4191
  // libs/auth/src/session/storage/storage-token-store.ts
4273
- var import_utils19 = require("@frontmcp/utils");
4192
+ var import_utils20 = require("@frontmcp/utils");
4274
4193
  var StorageTokenStore = class {
4275
4194
  storage;
4276
4195
  namespace;
@@ -4282,13 +4201,13 @@ var StorageTokenStore = class {
4282
4201
  this.defaultTtlSeconds = options.defaultTtlSeconds;
4283
4202
  this.storageIsNamespaced = "namespace" in storage && typeof storage.namespace === "function";
4284
4203
  const namespacedStorage = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
4285
- this.storage = new import_utils19.TypedStorage(namespacedStorage);
4204
+ this.storage = new import_utils20.TypedStorage(namespacedStorage);
4286
4205
  }
4287
4206
  /**
4288
4207
  * Allocate a new unique ID for a token record.
4289
4208
  */
4290
4209
  allocId() {
4291
- return (0, import_utils19.randomUUID)();
4210
+ return (0, import_utils20.randomUUID)();
4292
4211
  }
4293
4212
  /**
4294
4213
  * Store an encrypted token blob.
@@ -4351,7 +4270,7 @@ var StorageTokenStore = class {
4351
4270
  };
4352
4271
 
4353
4272
  // libs/auth/src/session/storage/storage-authorization-vault.ts
4354
- var import_utils20 = require("@frontmcp/utils");
4273
+ var import_utils21 = require("@frontmcp/utils");
4355
4274
  var StorageAuthorizationVault = class {
4356
4275
  storage;
4357
4276
  namespace;
@@ -4360,7 +4279,7 @@ var StorageAuthorizationVault = class {
4360
4279
  this.namespace = options.namespace ?? "vault";
4361
4280
  this.pendingAuthTtlMs = options.pendingAuthTtlMs ?? 10 * 60 * 1e3;
4362
4281
  const namespacedStorage = this.isNamespacedStorage(storage) ? storage.namespace(this.namespace) : storage;
4363
- this.storage = new import_utils20.TypedStorage(namespacedStorage, {
4282
+ this.storage = new import_utils21.TypedStorage(namespacedStorage, {
4364
4283
  schema: options.validateOnRead ? authorizationVaultEntrySchema : void 0,
4365
4284
  throwOnInvalid: false
4366
4285
  });
@@ -4371,7 +4290,7 @@ var StorageAuthorizationVault = class {
4371
4290
  async create(params) {
4372
4291
  const now = Date.now();
4373
4292
  const entry = {
4374
- id: (0, import_utils20.randomUUID)(),
4293
+ id: (0, import_utils21.randomUUID)(),
4375
4294
  userSub: params.userSub,
4376
4295
  userEmail: params.userEmail,
4377
4296
  userName: params.userName,
@@ -4445,7 +4364,7 @@ var StorageAuthorizationVault = class {
4445
4364
  }
4446
4365
  const now = Date.now();
4447
4366
  const pendingAuth = {
4448
- id: (0, import_utils20.randomUUID)(),
4367
+ id: (0, import_utils21.randomUUID)(),
4449
4368
  appId: params.appId,
4450
4369
  toolId: params.toolId,
4451
4370
  authUrl: params.authUrl,
@@ -4649,11 +4568,11 @@ var StorageAuthorizationVault = class {
4649
4568
  };
4650
4569
 
4651
4570
  // libs/auth/src/session/storage/in-memory-authorization-vault.ts
4652
- var import_utils21 = require("@frontmcp/utils");
4571
+ var import_utils22 = require("@frontmcp/utils");
4653
4572
  var InMemoryAuthorizationVault = class extends StorageAuthorizationVault {
4654
4573
  memoryAdapter;
4655
4574
  constructor(options = {}) {
4656
- const memoryAdapter = new import_utils21.MemoryStorageAdapter();
4575
+ const memoryAdapter = new import_utils22.MemoryStorageAdapter();
4657
4576
  super(memoryAdapter, {
4658
4577
  namespace: options.namespace ?? "vault",
4659
4578
  pendingAuthTtlMs: options.pendingAuthTtlMs
@@ -4674,7 +4593,7 @@ var InMemoryAuthorizationVault = class extends StorageAuthorizationVault {
4674
4593
  };
4675
4594
 
4676
4595
  // libs/auth/src/session/redis-session.store.ts
4677
- var import_utils24 = require("@frontmcp/utils");
4596
+ var import_utils25 = require("@frontmcp/utils");
4678
4597
  var RedisSessionStore = class {
4679
4598
  storage;
4680
4599
  keyPrefix;
@@ -4696,14 +4615,14 @@ var RedisSessionStore = class {
4696
4615
  });
4697
4616
  }
4698
4617
  if ("redis" in config && config.redis) {
4699
- this.storage = new import_utils24.RedisStorageAdapter({
4618
+ this.storage = new import_utils25.RedisStorageAdapter({
4700
4619
  client: config.redis,
4701
4620
  keyPrefix: this.keyPrefix
4702
4621
  });
4703
4622
  this.externalInstance = true;
4704
4623
  } else {
4705
4624
  const redisConfig = config;
4706
- this.storage = new import_utils24.RedisStorageAdapter({
4625
+ this.storage = new import_utils25.RedisStorageAdapter({
4707
4626
  config: {
4708
4627
  host: redisConfig.host,
4709
4628
  port: redisConfig.port ?? 6379,
@@ -4885,7 +4804,7 @@ var RedisSessionStore = class {
4885
4804
  * Allocate a new session ID
4886
4805
  */
4887
4806
  allocId() {
4888
- return (0, import_utils24.randomUUID)();
4807
+ return (0, import_utils25.randomUUID)();
4889
4808
  }
4890
4809
  /**
4891
4810
  * Disconnect from Redis (only if we created the connection)
@@ -4921,7 +4840,7 @@ var RedisSessionStore = class {
4921
4840
  };
4922
4841
 
4923
4842
  // libs/auth/src/session/vercel-kv-session.store.ts
4924
- var import_utils25 = require("@frontmcp/utils");
4843
+ var import_utils26 = require("@frontmcp/utils");
4925
4844
  var VercelKvSessionStore = class {
4926
4845
  storage;
4927
4846
  keyPrefix;
@@ -4941,7 +4860,7 @@ var VercelKvSessionStore = class {
4941
4860
  maxRequests: this.security.rateLimiting?.maxRequests
4942
4861
  });
4943
4862
  }
4944
- this.storage = new import_utils25.VercelKvStorageAdapter({
4863
+ this.storage = new import_utils26.VercelKvStorageAdapter({
4945
4864
  url: config.url,
4946
4865
  token: config.token,
4947
4866
  keyPrefix: this.keyPrefix
@@ -5115,7 +5034,7 @@ var VercelKvSessionStore = class {
5115
5034
  * Allocate a new session ID
5116
5035
  */
5117
5036
  allocId() {
5118
- return (0, import_utils25.randomUUID)();
5037
+ return (0, import_utils26.randomUUID)();
5119
5038
  }
5120
5039
  /**
5121
5040
  * Disconnect from Vercel KV
@@ -5144,7 +5063,7 @@ var VercelKvSessionStore = class {
5144
5063
  };
5145
5064
 
5146
5065
  // libs/auth/src/session/orchestrated-token.store.ts
5147
- var import_utils26 = require("@frontmcp/utils");
5066
+ var import_utils27 = require("@frontmcp/utils");
5148
5067
  var InMemoryOrchestratedTokenStore = class {
5149
5068
  /** Token storage: Map<compositeKey, ProviderTokenRecord> */
5150
5069
  tokens = /* @__PURE__ */ new Map();
@@ -5186,7 +5105,7 @@ var InMemoryOrchestratedTokenStore = class {
5186
5105
  }
5187
5106
  const info = new TextEncoder().encode(`orchestrated-token:${compositeKey}`);
5188
5107
  const salt = new TextEncoder().encode("frontmcp-token-store");
5189
- const derivedKey = (0, import_utils26.hkdfSha256)(this.encryptionKey, salt, info, 32);
5108
+ const derivedKey = (0, import_utils27.hkdfSha256)(this.encryptionKey, salt, info, 32);
5190
5109
  this.derivedKeys.set(compositeKey, derivedKey);
5191
5110
  return derivedKey;
5192
5111
  }
@@ -5196,8 +5115,8 @@ var InMemoryOrchestratedTokenStore = class {
5196
5115
  async encryptRecord(compositeKey, record) {
5197
5116
  const key = await this.deriveKeyForRecord(compositeKey);
5198
5117
  const plaintext = JSON.stringify(record);
5199
- const iv = (0, import_utils26.randomBytes)(12);
5200
- const { ciphertext, tag } = (0, import_utils26.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
5118
+ const iv = (0, import_utils27.randomBytes)(12);
5119
+ const { ciphertext, tag } = (0, import_utils27.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
5201
5120
  return JSON.stringify({
5202
5121
  iv: Buffer.from(iv).toString("base64url"),
5203
5122
  tag: Buffer.from(tag).toString("base64url"),
@@ -5213,7 +5132,7 @@ var InMemoryOrchestratedTokenStore = class {
5213
5132
  const ivBytes = Buffer.from(iv, "base64url");
5214
5133
  const tagBytes = Buffer.from(tag, "base64url");
5215
5134
  const ciphertextBytes = Buffer.from(data, "base64url");
5216
- const plaintext = (0, import_utils26.decryptAesGcm)(key, ciphertextBytes, ivBytes, tagBytes);
5135
+ const plaintext = (0, import_utils27.decryptAesGcm)(key, ciphertextBytes, ivBytes, tagBytes);
5217
5136
  return JSON.parse(new TextDecoder().decode(plaintext));
5218
5137
  }
5219
5138
  /**
@@ -5415,7 +5334,7 @@ var InMemoryOrchestratedTokenStore = class {
5415
5334
  };
5416
5335
 
5417
5336
  // libs/auth/src/session/orchestrated-token.crypto.ts
5418
- var import_utils27 = require("@frontmcp/utils");
5337
+ var import_utils28 = require("@frontmcp/utils");
5419
5338
  var HKDF_SALT = new TextEncoder().encode("frontmcp-token-store");
5420
5339
  function deriveKeyForRecord(masterKey, compositeKey, cache) {
5421
5340
  const cached = cache.get(compositeKey);
@@ -5423,14 +5342,14 @@ function deriveKeyForRecord(masterKey, compositeKey, cache) {
5423
5342
  return cached;
5424
5343
  }
5425
5344
  const info = new TextEncoder().encode(`orchestrated-token:${compositeKey}`);
5426
- const derived = (0, import_utils27.hkdfSha256)(masterKey, HKDF_SALT, info, 32);
5345
+ const derived = (0, import_utils28.hkdfSha256)(masterKey, HKDF_SALT, info, 32);
5427
5346
  cache.set(compositeKey, derived);
5428
5347
  return derived;
5429
5348
  }
5430
5349
  function encryptRecord(key, record) {
5431
5350
  const plaintext = JSON.stringify(record);
5432
- const iv = (0, import_utils27.randomBytes)(12);
5433
- const { ciphertext, tag } = (0, import_utils27.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
5351
+ const iv = (0, import_utils28.randomBytes)(12);
5352
+ const { ciphertext, tag } = (0, import_utils28.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
5434
5353
  return JSON.stringify({
5435
5354
  iv: Buffer.from(iv).toString("base64url"),
5436
5355
  tag: Buffer.from(tag).toString("base64url"),
@@ -5442,7 +5361,7 @@ function decryptRecord(key, encrypted) {
5442
5361
  const ivBytes = Buffer.from(iv, "base64url");
5443
5362
  const tagBytes = Buffer.from(tag, "base64url");
5444
5363
  const ciphertextBytes = Buffer.from(data, "base64url");
5445
- const plaintext = (0, import_utils27.decryptAesGcm)(key, ciphertextBytes, ivBytes, tagBytes);
5364
+ const plaintext = (0, import_utils28.decryptAesGcm)(key, ciphertextBytes, ivBytes, tagBytes);
5446
5365
  return JSON.parse(new TextDecoder().decode(plaintext));
5447
5366
  }
5448
5367
 
@@ -5621,7 +5540,7 @@ var StorageOrchestratedTokenStore = class {
5621
5540
  };
5622
5541
 
5623
5542
  // libs/auth/src/session/federated-auth.session.ts
5624
- var import_utils28 = require("@frontmcp/utils");
5543
+ var import_utils29 = require("@frontmcp/utils");
5625
5544
  function toSessionRecord(session) {
5626
5545
  return {
5627
5546
  ...session,
@@ -5696,7 +5615,7 @@ var InMemoryFederatedAuthSessionStore = class {
5696
5615
  createSession(params) {
5697
5616
  const now = Date.now();
5698
5617
  return {
5699
- id: (0, import_utils28.randomUUID)(),
5618
+ id: (0, import_utils29.randomUUID)(),
5700
5619
  pendingAuthId: params.pendingAuthId,
5701
5620
  clientId: params.clientId,
5702
5621
  redirectUri: params.redirectUri,
@@ -5728,7 +5647,7 @@ var InMemoryFederatedAuthSessionStore = class {
5728
5647
  function createFederatedAuthSession(params, ttlMs = 15 * 60 * 1e3) {
5729
5648
  const now = Date.now();
5730
5649
  return {
5731
- id: (0, import_utils28.randomUUID)(),
5650
+ id: (0, import_utils29.randomUUID)(),
5732
5651
  pendingAuthId: params.pendingAuthId,
5733
5652
  clientId: params.clientId,
5734
5653
  redirectUri: params.redirectUri,
@@ -5785,7 +5704,7 @@ function startNextProvider(session, pkce, state) {
5785
5704
  }
5786
5705
 
5787
5706
  // libs/auth/src/session/storage-federated-auth.session.ts
5788
- var import_utils29 = require("@frontmcp/utils");
5707
+ var import_utils30 = require("@frontmcp/utils");
5789
5708
  var StorageFederatedAuthSessionStore = class {
5790
5709
  storage;
5791
5710
  namespace;
@@ -5794,7 +5713,7 @@ var StorageFederatedAuthSessionStore = class {
5794
5713
  this.namespace = options.namespace ?? "fed";
5795
5714
  this.storageIsNamespaced = this.isNamespacedStorage(storage);
5796
5715
  const namespacedStorage = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
5797
- this.storage = new import_utils29.TypedStorage(namespacedStorage);
5716
+ this.storage = new import_utils30.TypedStorage(namespacedStorage);
5798
5717
  }
5799
5718
  async store(session) {
5800
5719
  await this.put(session);
@@ -5865,7 +5784,7 @@ var InMemoryConsentStore = class {
5865
5784
  };
5866
5785
 
5867
5786
  // libs/auth/src/session/storage-consent.store.ts
5868
- var import_utils30 = require("@frontmcp/utils");
5787
+ var import_utils31 = require("@frontmcp/utils");
5869
5788
  var StorageConsentStore = class {
5870
5789
  storage;
5871
5790
  namespace;
@@ -5874,7 +5793,7 @@ var StorageConsentStore = class {
5874
5793
  this.namespace = options.namespace ?? "remembered-consent";
5875
5794
  this.storageIsNamespaced = this.isNamespacedStorage(storage);
5876
5795
  const namespacedStorage = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
5877
- this.storage = new import_utils30.TypedStorage(namespacedStorage);
5796
+ this.storage = new import_utils31.TypedStorage(namespacedStorage);
5878
5797
  }
5879
5798
  async get(userSub, clientId) {
5880
5799
  return this.storage.get(this.key(userSub, clientId));
@@ -5896,7 +5815,7 @@ var StorageConsentStore = class {
5896
5815
 
5897
5816
  // libs/auth/src/session/encrypted-authorization-vault.ts
5898
5817
  var import_lazy_zod5 = require("@frontmcp/lazy-zod");
5899
- var import_utils31 = require("@frontmcp/utils");
5818
+ var import_utils32 = require("@frontmcp/utils");
5900
5819
  var redisVaultEntrySchema = import_lazy_zod5.z.object({
5901
5820
  /** Vault ID */
5902
5821
  id: import_lazy_zod5.z.string(),
@@ -5921,7 +5840,7 @@ var redisVaultEntrySchema = import_lazy_zod5.z.object({
5921
5840
  /** Encrypted sensitive data blob */
5922
5841
  encrypted: encryptedDataSchema
5923
5842
  });
5924
- var encryptionContextStorage = new import_utils31.AsyncLocalStorage();
5843
+ var encryptionContextStorage = new import_utils32.AsyncLocalStorage();
5925
5844
  var EncryptedRedisVault = class {
5926
5845
  constructor(redis, encryption, namespace = "vault:") {
5927
5846
  this.redis = redis;
@@ -6057,7 +5976,7 @@ var EncryptedRedisVault = class {
6057
5976
  async create(params) {
6058
5977
  const now = Date.now();
6059
5978
  const entry = {
6060
- id: (0, import_utils31.randomUUID)(),
5979
+ id: (0, import_utils32.randomUUID)(),
6061
5980
  userSub: params.userSub,
6062
5981
  userEmail: params.userEmail,
6063
5982
  userName: params.userName,
@@ -6116,7 +6035,7 @@ var EncryptedRedisVault = class {
6116
6035
  }
6117
6036
  const now = Date.now();
6118
6037
  const pendingAuth = {
6119
- id: (0, import_utils31.randomUUID)(),
6038
+ id: (0, import_utils32.randomUUID)(),
6120
6039
  appId: params.appId,
6121
6040
  toolId: params.toolId,
6122
6041
  authUrl: params.authUrl,
@@ -6294,7 +6213,7 @@ function createEncryptedVault(redis, config = {}) {
6294
6213
  }
6295
6214
 
6296
6215
  // libs/auth/src/session/token.refresh.ts
6297
- var import_utils32 = require("@frontmcp/utils");
6216
+ var import_utils33 = require("@frontmcp/utils");
6298
6217
  function toEpochSeconds(exp) {
6299
6218
  if (exp == null) return void 0;
6300
6219
  if (exp instanceof Date) return Math.floor(exp.getTime() / 1e3);
@@ -6316,7 +6235,7 @@ function tryJwtExp(token) {
6316
6235
  const parts = token.split(".");
6317
6236
  if (parts.length < 2) return void 0;
6318
6237
  try {
6319
- const json = JSON.parse(new TextDecoder().decode((0, import_utils32.base64urlDecode)(parts[1])));
6238
+ const json = JSON.parse(new TextDecoder().decode((0, import_utils33.base64urlDecode)(parts[1])));
6320
6239
  const e = json?.exp;
6321
6240
  return typeof e === "number" ? toEpochSeconds(e) : void 0;
6322
6241
  } catch {
@@ -6379,7 +6298,7 @@ var progressiveAuthStateSchema = import_lazy_zod6.z.object({
6379
6298
  });
6380
6299
 
6381
6300
  // libs/auth/src/authorization/authorization.class.ts
6382
- var import_utils35 = require("@frontmcp/utils");
6301
+ var import_utils36 = require("@frontmcp/utils");
6383
6302
  var AuthorizationBase = class _AuthorizationBase {
6384
6303
  id;
6385
6304
  isAnonymous;
@@ -6427,14 +6346,14 @@ var AuthorizationBase = class _AuthorizationBase {
6427
6346
  * @param fingerprint - Optional client fingerprint for tracking
6428
6347
  */
6429
6348
  createTransportSession(protocol, fingerprint) {
6430
- const sessionId = (0, import_utils35.randomUUID)();
6349
+ const sessionId = (0, import_utils36.randomUUID)();
6431
6350
  const session = {
6432
6351
  id: sessionId,
6433
6352
  authorizationId: this.id,
6434
6353
  protocol,
6435
6354
  createdAt: Date.now(),
6436
6355
  expiresAt: this.expiresAt,
6437
- nodeId: (0, import_utils35.getMachineId)(),
6356
+ nodeId: (0, import_utils36.getMachineId)(),
6438
6357
  clientFingerprint: fingerprint
6439
6358
  };
6440
6359
  this.#sessions.set(session.id, session);
@@ -6575,7 +6494,7 @@ var AuthorizationBase = class _AuthorizationBase {
6575
6494
  */
6576
6495
  static isJwtHeader(segment) {
6577
6496
  try {
6578
- const bytes = (0, import_utils35.base64urlDecode)(segment);
6497
+ const bytes = (0, import_utils36.base64urlDecode)(segment);
6579
6498
  const text = new TextDecoder().decode(bytes);
6580
6499
  const parsed = JSON.parse(text);
6581
6500
  return typeof parsed === "object" && parsed !== null && typeof parsed.alg === "string";
@@ -6627,7 +6546,7 @@ var AuthorizationBase = class _AuthorizationBase {
6627
6546
  };
6628
6547
 
6629
6548
  // libs/auth/src/authorization/public.authorization.ts
6630
- var import_utils36 = require("@frontmcp/utils");
6549
+ var import_utils37 = require("@frontmcp/utils");
6631
6550
  var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
6632
6551
  mode = "public";
6633
6552
  /**
@@ -6663,7 +6582,7 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
6663
6582
  allowedTools = "all",
6664
6583
  allowedPrompts = "all"
6665
6584
  } = ctx;
6666
- const uuid = (0, import_utils36.randomUUID)();
6585
+ const uuid = (0, import_utils37.randomUUID)();
6667
6586
  const sub = `${prefix}:${uuid}`;
6668
6587
  const user = {
6669
6588
  sub,
@@ -6747,7 +6666,7 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
6747
6666
  };
6748
6667
 
6749
6668
  // libs/auth/src/authorization/transparent.authorization.ts
6750
- var import_utils37 = require("@frontmcp/utils");
6669
+ var import_utils38 = require("@frontmcp/utils");
6751
6670
  var TransparentAuthorization = class _TransparentAuthorization extends AuthorizationBase {
6752
6671
  mode = "transparent";
6753
6672
  /**
@@ -6847,7 +6766,7 @@ var TransparentAuthorization = class _TransparentAuthorization extends Authoriza
6847
6766
  static generateAuthorizationId(token) {
6848
6767
  const parts = token.split(".");
6849
6768
  const signature = parts[2] || token;
6850
- return (0, import_utils37.sha256Hex)(signature).substring(0, 16);
6769
+ return (0, import_utils38.sha256Hex)(signature).substring(0, 16);
6851
6770
  }
6852
6771
  /**
6853
6772
  * Get the issuer from the token claims
@@ -6873,11 +6792,11 @@ var TransparentAuthorization = class _TransparentAuthorization extends Authoriza
6873
6792
  };
6874
6793
 
6875
6794
  // libs/auth/src/utils/authorization-id.utils.ts
6876
- var import_utils38 = require("@frontmcp/utils");
6795
+ var import_utils39 = require("@frontmcp/utils");
6877
6796
  function deriveAuthorizationId(token) {
6878
6797
  const parts = token.split(".");
6879
6798
  const signature = parts[2] || token;
6880
- return (0, import_utils38.sha256Hex)(signature).substring(0, 16);
6799
+ return (0, import_utils39.sha256Hex)(signature).substring(0, 16);
6881
6800
  }
6882
6801
 
6883
6802
  // libs/auth/src/authorization/orchestrated.authorization.ts
@@ -7246,7 +7165,7 @@ var OrchestratedAuthAccessorAdapter = class {
7246
7165
  };
7247
7166
 
7248
7167
  // libs/auth/src/authorization/dcr-client.registry.ts
7249
- var import_utils39 = require("@frontmcp/utils");
7168
+ var import_utils40 = require("@frontmcp/utils");
7250
7169
  var DEFAULT_MAX_DYNAMIC_CLIENTS = 1e3;
7251
7170
  function globMatch(pattern, input) {
7252
7171
  let p = 0;
@@ -7372,7 +7291,7 @@ var DcrClientRegistry = class {
7372
7291
  if (!isConfidential) return "ok";
7373
7292
  if (!client.client_secret) return "invalid";
7374
7293
  if (!presentedSecret) return "invalid";
7375
- return (0, import_utils39.timingSafeEqual)((0, import_utils39.sha256)(presentedSecret), (0, import_utils39.sha256)(client.client_secret)) ? "ok" : "invalid";
7294
+ return (0, import_utils40.timingSafeEqual)((0, import_utils40.sha256)(presentedSecret), (0, import_utils40.sha256)(client.client_secret)) ? "ok" : "invalid";
7376
7295
  }
7377
7296
  /** Whether a client id is known to the registry. */
7378
7297
  has(clientId) {
@@ -7460,7 +7379,7 @@ var DcrClientRegistry = class {
7460
7379
  if (typeof presented !== "string" || presented.length === 0) {
7461
7380
  return false;
7462
7381
  }
7463
- return (0, import_utils39.timingSafeEqual)((0, import_utils39.sha256)(presented), (0, import_utils39.sha256)(expected));
7382
+ return (0, import_utils40.timingSafeEqual)((0, import_utils40.sha256)(presented), (0, import_utils40.sha256)(expected));
7464
7383
  }
7465
7384
  };
7466
7385
 
@@ -7789,6 +7708,7 @@ var cimdConfigSchema = import_lazy_zod9.z.object({
7789
7708
  init_cimd_cache();
7790
7709
 
7791
7710
  // libs/auth/src/cimd/cimd.service.ts
7711
+ var import_utils41 = require("@frontmcp/utils");
7792
7712
  init_cimd_cache();
7793
7713
  var CimdService = class {
7794
7714
  config;
@@ -7963,7 +7883,7 @@ var CimdService = class {
7963
7883
  httpStatus: 304
7964
7884
  });
7965
7885
  }
7966
- if (response.status >= 300 && response.status < 400) {
7886
+ if ((0, import_utils41.isRedirectResponse)(response)) {
7967
7887
  const location = response.headers.get("location");
7968
7888
  if (!location) {
7969
7889
  throw new CimdFetchError(clientId, "Redirect response missing Location header", {
@@ -9548,7 +9468,7 @@ var CredentialCache = class {
9548
9468
  var AUTH_PROVIDERS_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:AUTH_PROVIDERS_ACCESSOR");
9549
9469
 
9550
9470
  // libs/auth/src/vault/auth-providers.accessor.impl.ts
9551
- var import_utils42 = require("@frontmcp/utils");
9471
+ var import_utils44 = require("@frontmcp/utils");
9552
9472
  var AuthProvidersAccessorImpl = class {
9553
9473
  constructor(registry, vault, cache, loader, context, logger) {
9554
9474
  this.registry = registry;
@@ -9763,7 +9683,7 @@ var AuthProvidersAccessorImpl = class {
9763
9683
  return { [credential.headerName]: credential.key };
9764
9684
  case "basic": {
9765
9685
  const value = `${credential.username}:${credential.password}`;
9766
- const encoded = credential.encodedValue ?? (0, import_utils42.base64Encode)(new TextEncoder().encode(value));
9686
+ const encoded = credential.encodedValue ?? (0, import_utils44.base64Encode)(new TextEncoder().encode(value));
9767
9687
  return { Authorization: `Basic ${encoded}` };
9768
9688
  }
9769
9689
  case "custom":
@@ -10351,6 +10271,18 @@ var noopRelationshipResolver = {
10351
10271
  return false;
10352
10272
  }
10353
10273
  };
10274
+ function resolveAuthUser(authInfo) {
10275
+ const extraUser = authInfo?.extra?.["user"];
10276
+ if (authInfo?.user) return authInfo.user;
10277
+ return typeof extraUser === "object" && extraUser !== null ? extraUser : {};
10278
+ }
10279
+ function isAnonymousSubject(sub) {
10280
+ return typeof sub !== "string" || sub === "" || sub.startsWith("anon:");
10281
+ }
10282
+ function signedInSubject(rawSub, mappedSub) {
10283
+ if (rawSub !== void 0 && isAnonymousSubject(rawSub)) return void 0;
10284
+ return [mappedSub, rawSub].find((candidate) => !isAnonymousSubject(candidate));
10285
+ }
10354
10286
  var AuthoritiesContextBuilder = class {
10355
10287
  claimsMapping;
10356
10288
  claimsResolver;
@@ -10368,7 +10300,7 @@ var AuthoritiesContextBuilder = class {
10368
10300
  const resolved = this.claimsResolver(authInfo);
10369
10301
  return {
10370
10302
  user: {
10371
- sub: authInfo?.user?.sub ?? "",
10303
+ sub: signedInSubject(resolveAuthUser(authInfo).sub),
10372
10304
  roles: resolved.roles,
10373
10305
  permissions: resolved.permissions,
10374
10306
  claims: resolved.claims
@@ -10378,7 +10310,7 @@ var AuthoritiesContextBuilder = class {
10378
10310
  relationships: this.relationshipResolver
10379
10311
  };
10380
10312
  }
10381
- const user = authInfo?.user ?? {};
10313
+ const user = resolveAuthUser(authInfo);
10382
10314
  const authorization = authInfo?.extra?.["authorization"];
10383
10315
  const authorizationClaims = authorization?.["claims"] ?? {};
10384
10316
  const rawClaims = {
@@ -10399,10 +10331,10 @@ var AuthoritiesContextBuilder = class {
10399
10331
  } else {
10400
10332
  permissions = toStringArray(user["permissions"] ?? []);
10401
10333
  }
10402
- const sub = this.claimsMapping?.userId ? String(resolveDotPath(rawClaims, this.claimsMapping.userId) ?? "") : user.sub ?? "";
10334
+ const mappedSub = this.claimsMapping?.userId ? resolveDotPath(rawClaims, this.claimsMapping.userId) : void 0;
10403
10335
  return {
10404
10336
  user: {
10405
- sub,
10337
+ sub: signedInSubject(user.sub, mappedSub),
10406
10338
  roles,
10407
10339
  permissions,
10408
10340
  claims: rawClaims
@@ -10434,15 +10366,17 @@ var FrontMcpAuthContextImpl = class {
10434
10366
  roles;
10435
10367
  permissions;
10436
10368
  constructor(source, claimsMapping) {
10437
- const rawUser = source.user ?? {};
10438
- const sub = claimsMapping?.userId ? String(resolveDotPath(this.buildRawClaims(source), claimsMapping.userId) ?? rawUser.sub ?? "") : String(rawUser.sub ?? "");
10369
+ const rawUser = resolveAuthUser(source);
10370
+ const mappedSub = claimsMapping?.userId ? resolveDotPath(this.buildRawClaims(source), claimsMapping.userId) : void 0;
10371
+ const signedInSub = signedInSubject(rawUser.sub, mappedSub);
10372
+ const sub = signedInSub ?? (typeof rawUser.sub === "string" ? rawUser.sub : "");
10439
10373
  this.user = Object.freeze({
10440
10374
  sub,
10441
10375
  name: rawUser.name,
10442
10376
  email: rawUser.email,
10443
10377
  picture: rawUser.picture
10444
10378
  });
10445
- this.isAnonymous = sub === "" || sub.startsWith("anon:");
10379
+ this.isAnonymous = signedInSub === void 0;
10446
10380
  const extraAuth = source.extra?.["authorization"];
10447
10381
  this.mode = String(
10448
10382
  source.extra?.["authMode"] ?? extraAuth?.["mode"] ?? (source.extra?.["isPublic"] === true || rawUser["anonymous"] === true ? "public" : "authenticated")
@@ -10500,7 +10434,7 @@ var FrontMcpAuthContextImpl = class {
10500
10434
  * Mirrors the logic in AuthoritiesContextBuilder.build().
10501
10435
  */
10502
10436
  buildRawClaims(source) {
10503
- const rawUser = source.user ?? {};
10437
+ const rawUser = resolveAuthUser(source);
10504
10438
  const extraAuth = source.extra?.["authorization"];
10505
10439
  const authorizationClaims = extraAuth?.["claims"] ?? {};
10506
10440
  return {
@@ -10719,8 +10653,9 @@ function resolveValue(value, ctx) {
10719
10653
  }
10720
10654
  function applyOperator(actual, op, expected) {
10721
10655
  switch (op) {
10656
+ // A missing expected value (e.g. an absent fromInput) never matches, even an absent actual value
10722
10657
  case "eq":
10723
- return actual === expected;
10658
+ return expected !== void 0 && actual === expected;
10724
10659
  case "neq":
10725
10660
  return actual !== expected;
10726
10661
  case "in":
@@ -10769,7 +10704,7 @@ function evaluateAbac(policy, ctx) {
10769
10704
  for (const [path, expectedRaw] of Object.entries(policy.match)) {
10770
10705
  const actual = resolveDotPath(envelope, path);
10771
10706
  const expected = resolveValue(expectedRaw, ctx);
10772
- if (actual !== expected) {
10707
+ if (expected === void 0 || actual !== expected) {
10773
10708
  return {
10774
10709
  granted: false,
10775
10710
  deniedBy: `attributes.match: '${path}' expected '${String(expected)}' but got '${String(actual)}'`,
@@ -10809,6 +10744,15 @@ function resolveResourceId(ref, ctx) {
10809
10744
  return void 0;
10810
10745
  }
10811
10746
  async function evaluateSingleRebac(policy, ctx) {
10747
+ const userSub = ctx.user.sub;
10748
+ if (userSub === void 0 || isAnonymousSubject(userSub)) {
10749
+ return {
10750
+ granted: false,
10751
+ deniedBy: `relationships: an anonymous caller cannot be '${policy.type}' of ${policy.resource}`,
10752
+ denial: { kind: "relationships", path: "user.sub", expected: "a signed-in caller", actual: void 0 },
10753
+ evaluatedPolicies: ["relationships"]
10754
+ };
10755
+ }
10812
10756
  const resourceId = resolveResourceId(policy.resourceId, ctx);
10813
10757
  if (resourceId === void 0) {
10814
10758
  return {
@@ -10823,11 +10767,11 @@ async function evaluateSingleRebac(policy, ctx) {
10823
10767
  evaluatedPolicies: ["relationships"]
10824
10768
  };
10825
10769
  }
10826
- const hasRelationship = await ctx.relationships.check(policy.type, policy.resource, resourceId, ctx.user.sub, ctx);
10770
+ const hasRelationship = await ctx.relationships.check(policy.type, policy.resource, resourceId, userSub, ctx);
10827
10771
  if (!hasRelationship) {
10828
10772
  return {
10829
10773
  granted: false,
10830
- deniedBy: `relationships: user '${ctx.user.sub}' is not '${policy.type}' of ${policy.resource}:${resourceId}`,
10774
+ deniedBy: `relationships: user '${userSub}' is not '${policy.type}' of ${policy.resource}:${resourceId}`,
10831
10775
  denial: {
10832
10776
  kind: "relationships",
10833
10777
  path: "relationships",
@@ -11501,6 +11445,7 @@ var FetchCredentialMiddleware = class {
11501
11445
  headerApplier,
11502
11446
  hkdfSha256,
11503
11447
  incrementalAuthConfigSchema,
11448
+ isAnonymousSubject,
11504
11449
  isCimdClientId,
11505
11450
  isFrontMcpCredentials,
11506
11451
  isJwt,