@frontmcp/auth 1.7.2 → 1.8.1
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/authorities/authorities.context.d.ts +16 -1
- package/authorities/authorities.context.d.ts.map +1 -1
- package/authorities/authorities.evaluator.d.ts +1 -1
- package/authorities/authorities.evaluator.d.ts.map +1 -1
- package/authorities/authorities.types.d.ts +2 -2
- package/authorities/authorities.types.d.ts.map +1 -1
- package/authorities/index.d.ts +1 -1
- package/authorities/index.d.ts.map +1 -1
- package/cimd/cimd.service.d.ts.map +1 -1
- package/cimd/cimd.validator.d.ts.map +1 -1
- package/context/frontmcp-auth-context.impl.d.ts.map +1 -1
- package/detection/auth-provider-detection.d.ts +2 -0
- package/detection/auth-provider-detection.d.ts.map +1 -1
- package/errors/auth-internal.errors.d.ts +12 -0
- package/errors/auth-internal.errors.d.ts.map +1 -1
- package/errors/index.d.ts +1 -1
- package/errors/index.d.ts.map +1 -1
- package/esm/index.mjs +306 -247
- package/esm/package.json +5 -5
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +459 -396
- package/jwks/jwks.service.d.ts.map +1 -1
- package/options/index.d.ts +4 -2
- package/options/index.d.ts.map +1 -1
- package/options/interfaces.d.ts +20 -2
- package/options/interfaces.d.ts.map +1 -1
- package/options/schema.d.ts +13 -1
- package/options/schema.d.ts.map +1 -1
- package/options/static.schema.d.ts +27 -0
- package/options/static.schema.d.ts.map +1 -0
- package/options/typecheck.d.ts.map +1 -1
- package/options/utils.d.ts +7 -2
- package/options/utils.d.ts.map +1 -1
- package/package.json +5 -5
- package/session/authorization-vault.d.ts +1 -1
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: () =>
|
|
272
|
+
EncryptedStorageError: () => import_utils24.EncryptedStorageError,
|
|
273
273
|
EncryptedStorageSecureStoreBackend: () => EncryptedStorageSecureStoreBackend,
|
|
274
|
-
EncryptedTypedStorage: () =>
|
|
274
|
+
EncryptedTypedStorage: () => import_utils24.EncryptedTypedStorage,
|
|
275
275
|
EncryptionContextNotSetError: () => EncryptionContextNotSetError,
|
|
276
276
|
EncryptionKeyNotConfiguredError: () => EncryptionKeyNotConfiguredError,
|
|
277
277
|
FetchCredentialMiddleware: () => FetchCredentialMiddleware,
|
|
@@ -285,6 +285,8 @@ __export(index_exports, {
|
|
|
285
285
|
InMemoryStoreRequiredError: () => InMemoryStoreRequiredError,
|
|
286
286
|
InvalidClientIdUrlError: () => InvalidClientIdUrlError,
|
|
287
287
|
JwksService: () => JwksService,
|
|
288
|
+
JwtSecretRequiredError: () => JwtSecretRequiredError,
|
|
289
|
+
JwtSecretWeakError: () => JwtSecretWeakError,
|
|
288
290
|
LazyCredentialLoader: () => LazyCredentialLoader,
|
|
289
291
|
NoProviderIdError: () => NoProviderIdError,
|
|
290
292
|
NullOrchestratedAuthAccessor: () => NullOrchestratedAuthAccessor,
|
|
@@ -317,7 +319,7 @@ __export(index_exports, {
|
|
|
317
319
|
TokenVault: () => TokenVault,
|
|
318
320
|
TransparentAuthorization: () => TransparentAuthorization,
|
|
319
321
|
TransportIdGenerator: () => TransportIdGenerator,
|
|
320
|
-
TypedStorage: () =>
|
|
322
|
+
TypedStorage: () => import_utils23.TypedStorage,
|
|
321
323
|
VaultEncryption: () => VaultEncryption,
|
|
322
324
|
VaultLoadError: () => VaultLoadError,
|
|
323
325
|
VaultNotFoundError: () => VaultNotFoundError,
|
|
@@ -399,9 +401,9 @@ __export(index_exports, {
|
|
|
399
401
|
credentialTypeSchema: () => credentialTypeSchema,
|
|
400
402
|
customCredentialSchema: () => customCredentialSchema,
|
|
401
403
|
decodeJwtPayloadSafe: () => decodeJwtPayloadSafe,
|
|
402
|
-
decryptAesGcm: () =>
|
|
404
|
+
decryptAesGcm: () => import_utils34.decryptAesGcm,
|
|
403
405
|
decryptSessionJson: () => decryptSessionJson,
|
|
404
|
-
decryptValue: () =>
|
|
406
|
+
decryptValue: () => import_utils34.decryptValue,
|
|
405
407
|
defaultSessionRateLimiter: () => defaultSessionRateLimiter,
|
|
406
408
|
deriveAuthorizationId: () => deriveAuthorizationId,
|
|
407
409
|
deriveExpectedAudience: () => deriveExpectedAudience,
|
|
@@ -409,13 +411,13 @@ __export(index_exports, {
|
|
|
409
411
|
deriveTypedUser: () => deriveTypedUser,
|
|
410
412
|
detectAuthProviders: () => detectAuthProviders,
|
|
411
413
|
detectedAuthProviderSchema: () => detectedAuthProviderSchema,
|
|
412
|
-
encryptAesGcm: () =>
|
|
414
|
+
encryptAesGcm: () => import_utils34.encryptAesGcm,
|
|
413
415
|
encryptJson: () => encryptJson,
|
|
414
|
-
encryptValue: () =>
|
|
416
|
+
encryptValue: () => import_utils34.encryptValue,
|
|
415
417
|
encryptedBlobSchema: () => encryptedBlobSchema,
|
|
416
418
|
encryptedDataSchema: () => encryptedDataSchema,
|
|
417
419
|
encryptedVaultEntrySchema: () => encryptedVaultEntrySchema,
|
|
418
|
-
escapeHtml: () =>
|
|
420
|
+
escapeHtml: () => import_utils4.escapeHtml,
|
|
419
421
|
extraWideLayout: () => extraWideLayout,
|
|
420
422
|
extractBearerToken: () => extractBearerToken,
|
|
421
423
|
extractCacheHeaders: () => extractCacheHeaders,
|
|
@@ -437,8 +439,9 @@ __export(index_exports, {
|
|
|
437
439
|
getTokenSignatureFingerprint: () => getTokenSignatureFingerprint,
|
|
438
440
|
hasOnlyLocalhostRedirectUris: () => hasOnlyLocalhostRedirectUris,
|
|
439
441
|
headerApplier: () => headerApplier,
|
|
440
|
-
hkdfSha256: () =>
|
|
442
|
+
hkdfSha256: () => import_utils34.hkdfSha256,
|
|
441
443
|
incrementalAuthConfigSchema: () => incrementalAuthConfigSchema,
|
|
444
|
+
isAnonymousSubject: () => isAnonymousSubject,
|
|
442
445
|
isCimdClientId: () => isCimdClientId,
|
|
443
446
|
isFrontMcpCredentials: () => isFrontMcpCredentials,
|
|
444
447
|
isJwt: () => isJwt,
|
|
@@ -451,10 +454,11 @@ __export(index_exports, {
|
|
|
451
454
|
isRedisTokenStorage: () => isRedisTokenStorage,
|
|
452
455
|
isRemoteMode: () => isRemoteMode,
|
|
453
456
|
isSessionComplete: () => isSessionComplete,
|
|
454
|
-
isSignedSession: () =>
|
|
457
|
+
isSignedSession: () => import_utils16.isSignedData,
|
|
455
458
|
isSoonExpiring: () => isSoonExpiring,
|
|
456
459
|
isSoonExpiringProvider: () => isSoonExpiringProvider,
|
|
457
460
|
isSqliteTokenStorage: () => isSqliteTokenStorage,
|
|
461
|
+
isStaticMode: () => isStaticMode,
|
|
458
462
|
isTransparentMode: () => isTransparentMode,
|
|
459
463
|
jsonWebKeySetSchema: () => jsonWebKeySetSchema,
|
|
460
464
|
jwkParametersSchema: () => jwkParametersSchema,
|
|
@@ -514,6 +518,7 @@ __export(index_exports, {
|
|
|
514
518
|
startNextProvider: () => startNextProvider,
|
|
515
519
|
statefulHttpTransportStateSchema: () => statefulHttpTransportStateSchema,
|
|
516
520
|
statelessHttpTransportStateSchema: () => statelessHttpTransportStateSchema,
|
|
521
|
+
staticAuthOptionsSchema: () => staticAuthOptionsSchema,
|
|
517
522
|
storedSessionSchema: () => storedSessionSchema,
|
|
518
523
|
streamableHttpTransportStateSchema: () => streamableHttpTransportStateSchema,
|
|
519
524
|
toEpochSeconds: () => toEpochSeconds,
|
|
@@ -545,6 +550,9 @@ module.exports = __toCommonJS(index_exports);
|
|
|
545
550
|
|
|
546
551
|
// libs/auth/src/jwks/jwks.service.ts
|
|
547
552
|
var import_jose = require("jose");
|
|
553
|
+
var import_utils2 = require("@frontmcp/utils");
|
|
554
|
+
|
|
555
|
+
// libs/auth/src/cimd/cimd.validator.ts
|
|
548
556
|
var import_utils = require("@frontmcp/utils");
|
|
549
557
|
|
|
550
558
|
// libs/auth/src/cimd/cimd.errors.ts
|
|
@@ -810,70 +818,38 @@ function isIpAddress(hostname) {
|
|
|
810
818
|
}
|
|
811
819
|
return false;
|
|
812
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
|
+
]);
|
|
813
837
|
function checkIpAddress(ip) {
|
|
814
|
-
const
|
|
815
|
-
if (
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
const parts = ip.split(".").map(Number);
|
|
822
|
-
if (parts.length !== 4 || parts.some((p) => isNaN(p) || p < 0 || p > 255)) {
|
|
823
|
-
return { allowed: false, reason: "Invalid IPv4 address" };
|
|
824
|
-
}
|
|
825
|
-
const [a, b, c, d] = parts;
|
|
826
|
-
if (a === 127) {
|
|
827
|
-
return { allowed: false, reason: "Loopback addresses (127.x.x.x) are not allowed" };
|
|
828
|
-
}
|
|
829
|
-
if (a === 10) {
|
|
830
|
-
return { allowed: false, reason: "Private IP addresses (10.x.x.x) are not allowed" };
|
|
831
|
-
}
|
|
832
|
-
if (a === 172 && b >= 16 && b <= 31) {
|
|
833
|
-
return { allowed: false, reason: "Private IP addresses (172.16-31.x.x) are not allowed" };
|
|
834
|
-
}
|
|
835
|
-
if (a === 192 && b === 168) {
|
|
836
|
-
return { allowed: false, reason: "Private IP addresses (192.168.x.x) are not allowed" };
|
|
837
|
-
}
|
|
838
|
-
if (a === 169 && b === 254) {
|
|
839
|
-
return { allowed: false, reason: "Link-local addresses (169.254.x.x) are not allowed" };
|
|
840
|
-
}
|
|
841
|
-
if (a === 100 && b >= 64 && b <= 127) {
|
|
842
|
-
return { allowed: false, reason: "Carrier-grade NAT addresses (100.64-127.x.x) are not allowed" };
|
|
843
|
-
}
|
|
844
|
-
if (a === 192 && b === 0 && c === 0) {
|
|
845
|
-
return { allowed: false, reason: "IETF protocol-assignment addresses (192.0.0.0/24) are not allowed" };
|
|
846
|
-
}
|
|
847
|
-
if (a === 0) {
|
|
848
|
-
return { allowed: false, reason: "Current network addresses (0.x.x.x) are not allowed" };
|
|
849
|
-
}
|
|
850
|
-
if (a === 255 && b === 255 && c === 255 && d === 255) {
|
|
851
|
-
return { allowed: false, reason: "Broadcast address is not allowed" };
|
|
852
|
-
}
|
|
853
|
-
if (a >= 224 && a <= 239) {
|
|
854
|
-
return { allowed: false, reason: "Multicast addresses are not allowed" };
|
|
855
|
-
}
|
|
856
|
-
return { allowed: true, reason: "" };
|
|
857
|
-
}
|
|
858
|
-
function checkIpv6(ip) {
|
|
859
|
-
const normalizedIp = ip.toLowerCase();
|
|
860
|
-
if (normalizedIp === "::1") {
|
|
861
|
-
return { allowed: false, reason: "IPv6 loopback address (::1) is not allowed" };
|
|
862
|
-
}
|
|
863
|
-
if (normalizedIp === "::" || normalizedIp === "0:0:0:0:0:0:0:0") {
|
|
864
|
-
return { allowed: false, reason: "IPv6 unspecified address (::) is not allowed" };
|
|
865
|
-
}
|
|
866
|
-
if (normalizedIp.startsWith("fe8") || normalizedIp.startsWith("fe9") || normalizedIp.startsWith("fea") || normalizedIp.startsWith("feb")) {
|
|
867
|
-
return { allowed: false, reason: "IPv6 link-local addresses (fe80::/10) are not allowed" };
|
|
868
|
-
}
|
|
869
|
-
if (normalizedIp.startsWith("fc") || normalizedIp.startsWith("fd")) {
|
|
870
|
-
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
|
+
};
|
|
871
845
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
return checkIpv4(ipv4MappedMatch[1]);
|
|
846
|
+
if (classification.range === "public") {
|
|
847
|
+
return { allowed: true, reason: "" };
|
|
875
848
|
}
|
|
876
|
-
return {
|
|
849
|
+
return {
|
|
850
|
+
allowed: false,
|
|
851
|
+
reason: BLOCKED_RANGE_REASONS.get(classification.cidr) ?? `Addresses in the ${classification.range} range (${classification.cidr}) are not allowed`
|
|
852
|
+
};
|
|
877
853
|
}
|
|
878
854
|
function isDomainInList(hostname, domainList) {
|
|
879
855
|
const lowerHostname = hostname.toLowerCase();
|
|
@@ -1004,9 +980,9 @@ var JwksService = class {
|
|
|
1004
980
|
* Returns null if persistence is disabled (production).
|
|
1005
981
|
*/
|
|
1006
982
|
async getKeyPersistence() {
|
|
1007
|
-
if ((0,
|
|
983
|
+
if ((0, import_utils2.isProduction)()) return null;
|
|
1008
984
|
if (!this.keyPersistence) {
|
|
1009
|
-
this.keyPersistence = await (0,
|
|
985
|
+
this.keyPersistence = await (0, import_utils2.createKeyPersistence)({
|
|
1010
986
|
baseDir: ".frontmcp/keys"
|
|
1011
987
|
});
|
|
1012
988
|
}
|
|
@@ -1125,7 +1101,7 @@ var JwksService = class {
|
|
|
1125
1101
|
if (!jwtAlg) {
|
|
1126
1102
|
return { ok: false, error: "missing_alg" };
|
|
1127
1103
|
}
|
|
1128
|
-
const isValid = await (0,
|
|
1104
|
+
const isValid = await (0, import_utils2.rsaVerify)(
|
|
1129
1105
|
jwtAlg,
|
|
1130
1106
|
Buffer.from(signatureInput),
|
|
1131
1107
|
matchingKey,
|
|
@@ -1268,10 +1244,10 @@ var JwksService = class {
|
|
|
1268
1244
|
const parsed = new URL(currentUrl);
|
|
1269
1245
|
const host = parsed.hostname.toLowerCase();
|
|
1270
1246
|
const isLocalhost = host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
|
|
1271
|
-
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && (isLocalhost || !(0,
|
|
1247
|
+
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && (isLocalhost || !(0, import_utils2.isProduction)()))) {
|
|
1272
1248
|
throw new Error(`insecure scheme "${parsed.protocol}"`);
|
|
1273
1249
|
}
|
|
1274
|
-
if (!(isLocalhost && !(0,
|
|
1250
|
+
if (!(isLocalhost && !(0, import_utils2.isProduction)())) {
|
|
1275
1251
|
const ssrf = await resolveAndCheckHostname(parsed.hostname);
|
|
1276
1252
|
if (!ssrf.allowed) throw new Error(`blocked host: ${ssrf.reason}`);
|
|
1277
1253
|
}
|
|
@@ -1282,11 +1258,10 @@ var JwksService = class {
|
|
|
1282
1258
|
// Follow redirects manually so each hop is re-validated (scheme + SSRF).
|
|
1283
1259
|
redirect: "manual"
|
|
1284
1260
|
});
|
|
1285
|
-
if (
|
|
1261
|
+
if ((0, import_utils2.isRedirectResponse)(res)) {
|
|
1286
1262
|
const location = res.headers.get("location");
|
|
1287
|
-
if (!location
|
|
1288
|
-
|
|
1289
|
-
}
|
|
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");
|
|
1290
1265
|
currentUrl = new URL(location, currentUrl).toString();
|
|
1291
1266
|
continue;
|
|
1292
1267
|
}
|
|
@@ -1379,13 +1354,13 @@ var JwksService = class {
|
|
|
1379
1354
|
const { generateKeyPairSync } = require("node:crypto");
|
|
1380
1355
|
if (alg === "RS256") {
|
|
1381
1356
|
const { privateKey, publicKey } = generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
1382
|
-
const kid = (0,
|
|
1357
|
+
const kid = (0, import_utils2.bytesToHex)((0, import_utils2.randomBytes)(8));
|
|
1383
1358
|
const publicJwk = publicKey.export({ format: "jwk" });
|
|
1384
1359
|
Object.assign(publicJwk, { kid, alg: "RS256", use: "sig", kty: "RSA" });
|
|
1385
1360
|
return { kid, privateKey, publicJwk: { keys: [publicJwk] }, createdAt: Date.now() };
|
|
1386
1361
|
} else {
|
|
1387
1362
|
const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
1388
|
-
const kid = (0,
|
|
1363
|
+
const kid = (0, import_utils2.bytesToHex)((0, import_utils2.randomBytes)(8));
|
|
1389
1364
|
const publicJwk = publicKey.export({ format: "jwk" });
|
|
1390
1365
|
Object.assign(publicJwk, { kid, alg: "ES256", use: "sig", kty: "EC" });
|
|
1391
1366
|
return { kid, privateKey, publicJwk: { keys: [publicJwk] }, createdAt: Date.now() };
|
|
@@ -1394,8 +1369,8 @@ var JwksService = class {
|
|
|
1394
1369
|
};
|
|
1395
1370
|
|
|
1396
1371
|
// libs/auth/src/ui/base-layout.ts
|
|
1397
|
-
var import_utils2 = require("@frontmcp/utils");
|
|
1398
1372
|
var import_utils3 = require("@frontmcp/utils");
|
|
1373
|
+
var import_utils4 = require("@frontmcp/utils");
|
|
1399
1374
|
var CDN = {
|
|
1400
1375
|
/** Tailwind CSS v4 Browser CDN - generates styles on-the-fly with @theme support */
|
|
1401
1376
|
tailwind: "https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4",
|
|
@@ -1474,13 +1449,13 @@ function baseLayout(content, options) {
|
|
|
1474
1449
|
}
|
|
1475
1450
|
${customCss}
|
|
1476
1451
|
</style>` : "";
|
|
1477
|
-
const metaDescription = description ? `<meta name="description" content="${(0,
|
|
1452
|
+
const metaDescription = description ? `<meta name="description" content="${(0, import_utils3.escapeHtml)(description)}">` : "";
|
|
1478
1453
|
return `<!DOCTYPE html>
|
|
1479
1454
|
<html lang="en">
|
|
1480
1455
|
<head>
|
|
1481
1456
|
<meta charset="UTF-8">
|
|
1482
1457
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1483
|
-
<title>${(0,
|
|
1458
|
+
<title>${(0, import_utils3.escapeHtml)(title)} - FrontMCP</title>
|
|
1484
1459
|
${metaDescription}
|
|
1485
1460
|
|
|
1486
1461
|
<!-- Google Fonts CDN - Inter (modern UI font) -->
|
|
@@ -1491,7 +1466,7 @@ function baseLayout(content, options) {
|
|
|
1491
1466
|
${tailwindBlock}
|
|
1492
1467
|
${headExtra}
|
|
1493
1468
|
</head>
|
|
1494
|
-
<body class="${(0,
|
|
1469
|
+
<body class="${(0, import_utils3.escapeHtml)(bodyClass)}">
|
|
1495
1470
|
${content}
|
|
1496
1471
|
</body>
|
|
1497
1472
|
</html>`;
|
|
@@ -1546,7 +1521,7 @@ function extraWideLayout(content, options) {
|
|
|
1546
1521
|
}
|
|
1547
1522
|
|
|
1548
1523
|
// libs/auth/src/ui/templates.ts
|
|
1549
|
-
var escapeHtml3 =
|
|
1524
|
+
var escapeHtml3 = import_utils4.escapeHtml;
|
|
1550
1525
|
function buildConsentPage(params) {
|
|
1551
1526
|
const { apps, clientName, pendingAuthId, csrfToken, callbackPath } = params;
|
|
1552
1527
|
const appCards = apps.map((app) => buildAppCardHtml(app, pendingAuthId, csrfToken, callbackPath)).join("\n");
|
|
@@ -2048,7 +2023,7 @@ function renderLocalLoginPage(login, ctx, values) {
|
|
|
2048
2023
|
|
|
2049
2024
|
// libs/auth/src/session/authorization.store.ts
|
|
2050
2025
|
var import_lazy_zod = require("@frontmcp/lazy-zod");
|
|
2051
|
-
var
|
|
2026
|
+
var import_utils5 = require("@frontmcp/utils");
|
|
2052
2027
|
var pkceChallengeSchema = import_lazy_zod.z.object({
|
|
2053
2028
|
challenge: import_lazy_zod.z.string().min(43).max(128),
|
|
2054
2029
|
method: import_lazy_zod.z.literal("S256")
|
|
@@ -2083,10 +2058,10 @@ var AUTH_CODE_TTL_MS = 60 * 1e3;
|
|
|
2083
2058
|
var PENDING_AUTH_TTL_MS = 10 * 60 * 1e3;
|
|
2084
2059
|
var REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
2085
2060
|
function generateAuthorizationCode() {
|
|
2086
|
-
return (0,
|
|
2061
|
+
return (0, import_utils5.randomUUID)().replace(/-/g, "") + (0, import_utils5.randomUUID)().replace(/-/g, "");
|
|
2087
2062
|
}
|
|
2088
2063
|
function generateRefreshTokenValue() {
|
|
2089
|
-
return (0,
|
|
2064
|
+
return (0, import_utils5.randomUUID)() + "-" + (0, import_utils5.randomUUID)();
|
|
2090
2065
|
}
|
|
2091
2066
|
function buildCodeRecord(params) {
|
|
2092
2067
|
const now = Date.now();
|
|
@@ -2117,7 +2092,7 @@ function buildCodeRecord(params) {
|
|
|
2117
2092
|
function buildPendingRecord(params) {
|
|
2118
2093
|
const now = Date.now();
|
|
2119
2094
|
return {
|
|
2120
|
-
id: (0,
|
|
2095
|
+
id: (0, import_utils5.randomUUID)(),
|
|
2121
2096
|
clientId: params.clientId,
|
|
2122
2097
|
redirectUri: params.redirectUri,
|
|
2123
2098
|
scopes: params.scopes,
|
|
@@ -2166,11 +2141,11 @@ function verifyPkce(codeVerifier, challenge) {
|
|
|
2166
2141
|
if (challenge.method !== "S256") {
|
|
2167
2142
|
return false;
|
|
2168
2143
|
}
|
|
2169
|
-
const hash = (0,
|
|
2144
|
+
const hash = (0, import_utils5.sha256Base64url)(codeVerifier);
|
|
2170
2145
|
return hash === challenge.challenge;
|
|
2171
2146
|
}
|
|
2172
2147
|
function generatePkceChallenge(codeVerifier) {
|
|
2173
|
-
const challenge = (0,
|
|
2148
|
+
const challenge = (0, import_utils5.sha256Base64url)(codeVerifier);
|
|
2174
2149
|
return { challenge, method: "S256" };
|
|
2175
2150
|
}
|
|
2176
2151
|
var InMemoryAuthorizationStore = class {
|
|
@@ -2366,7 +2341,7 @@ var RedisAuthorizationStore = class {
|
|
|
2366
2341
|
};
|
|
2367
2342
|
|
|
2368
2343
|
// libs/auth/src/session/storage-authorization.store.ts
|
|
2369
|
-
var
|
|
2344
|
+
var import_utils6 = require("@frontmcp/utils");
|
|
2370
2345
|
var StorageAuthorizationStore = class {
|
|
2371
2346
|
codeStore;
|
|
2372
2347
|
pendingStore;
|
|
@@ -2377,9 +2352,9 @@ var StorageAuthorizationStore = class {
|
|
|
2377
2352
|
this.namespace = options.namespace ?? "oauth";
|
|
2378
2353
|
this.storageIsNamespaced = this.isNamespacedStorage(storage);
|
|
2379
2354
|
const base = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
|
|
2380
|
-
this.codeStore = new
|
|
2381
|
-
this.pendingStore = new
|
|
2382
|
-
this.refreshStore = new
|
|
2355
|
+
this.codeStore = new import_utils6.TypedStorage(base);
|
|
2356
|
+
this.pendingStore = new import_utils6.TypedStorage(base);
|
|
2357
|
+
this.refreshStore = new import_utils6.TypedStorage(base);
|
|
2383
2358
|
}
|
|
2384
2359
|
// ============================================
|
|
2385
2360
|
// Record builders (pure; shared with in-memory store)
|
|
@@ -2752,11 +2727,11 @@ var authorizationVaultEntrySchema = import_lazy_zod2.z.object({
|
|
|
2752
2727
|
});
|
|
2753
2728
|
|
|
2754
2729
|
// libs/auth/src/session/session-credential-vault.ts
|
|
2755
|
-
var
|
|
2730
|
+
var import_utils8 = require("@frontmcp/utils");
|
|
2756
2731
|
|
|
2757
2732
|
// libs/auth/src/session/vault-encryption.ts
|
|
2758
2733
|
var import_lazy_zod3 = require("@frontmcp/lazy-zod");
|
|
2759
|
-
var
|
|
2734
|
+
var import_utils7 = require("@frontmcp/utils");
|
|
2760
2735
|
var encryptedDataSchema = import_lazy_zod3.z.object({
|
|
2761
2736
|
/** Version for future algorithm changes */
|
|
2762
2737
|
v: import_lazy_zod3.z.literal(1),
|
|
@@ -2796,7 +2771,7 @@ var VaultEncryption = class {
|
|
|
2796
2771
|
];
|
|
2797
2772
|
const ikm = new TextEncoder().encode(ikmParts.join(""));
|
|
2798
2773
|
const infoBytes = new TextEncoder().encode(this.hkdfInfo);
|
|
2799
|
-
const key = await (0,
|
|
2774
|
+
const key = await (0, import_utils7.hkdfSha256)(ikm, new Uint8Array(0), infoBytes, 32);
|
|
2800
2775
|
return key;
|
|
2801
2776
|
}
|
|
2802
2777
|
/**
|
|
@@ -2823,7 +2798,7 @@ var VaultEncryption = class {
|
|
|
2823
2798
|
];
|
|
2824
2799
|
const ikm = new TextEncoder().encode(ikmParts.join(""));
|
|
2825
2800
|
const infoBytes = new TextEncoder().encode(this.hkdfInfo);
|
|
2826
|
-
const key = await (0,
|
|
2801
|
+
const key = await (0, import_utils7.hkdfSha256)(ikm, new Uint8Array(0), infoBytes, 32);
|
|
2827
2802
|
return key;
|
|
2828
2803
|
}
|
|
2829
2804
|
/**
|
|
@@ -2837,14 +2812,14 @@ var VaultEncryption = class {
|
|
|
2837
2812
|
if (key.length !== 32) {
|
|
2838
2813
|
throw new Error("Encryption key must be 32 bytes");
|
|
2839
2814
|
}
|
|
2840
|
-
const iv = (0,
|
|
2841
|
-
const { ciphertext, tag } = await (0,
|
|
2815
|
+
const iv = (0, import_utils7.randomBytes)(12);
|
|
2816
|
+
const { ciphertext, tag } = await (0, import_utils7.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
|
|
2842
2817
|
return {
|
|
2843
2818
|
v: 1,
|
|
2844
2819
|
alg: "aes-256-gcm",
|
|
2845
|
-
iv: (0,
|
|
2846
|
-
ct: (0,
|
|
2847
|
-
tag: (0,
|
|
2820
|
+
iv: (0, import_utils7.base64urlEncode)(iv),
|
|
2821
|
+
ct: (0, import_utils7.base64urlEncode)(ciphertext),
|
|
2822
|
+
tag: (0, import_utils7.base64urlEncode)(tag)
|
|
2848
2823
|
};
|
|
2849
2824
|
}
|
|
2850
2825
|
/**
|
|
@@ -2864,11 +2839,11 @@ var VaultEncryption = class {
|
|
|
2864
2839
|
throw new Error("Invalid encrypted data format");
|
|
2865
2840
|
}
|
|
2866
2841
|
const { iv, ct, tag } = parsed.data;
|
|
2867
|
-
const ivBuffer = (0,
|
|
2868
|
-
const ciphertext = (0,
|
|
2869
|
-
const tagBuffer = (0,
|
|
2842
|
+
const ivBuffer = (0, import_utils7.base64urlDecode)(iv);
|
|
2843
|
+
const ciphertext = (0, import_utils7.base64urlDecode)(ct);
|
|
2844
|
+
const tagBuffer = (0, import_utils7.base64urlDecode)(tag);
|
|
2870
2845
|
try {
|
|
2871
|
-
const plaintext = await (0,
|
|
2846
|
+
const plaintext = await (0, import_utils7.decryptAesGcm)(key, ciphertext, ivBuffer, tagBuffer);
|
|
2872
2847
|
return new TextDecoder().decode(plaintext);
|
|
2873
2848
|
} catch (_error) {
|
|
2874
2849
|
throw new Error("Decryption failed: invalid key or corrupted data");
|
|
@@ -3008,7 +2983,7 @@ var SessionCredentialVault = class {
|
|
|
3008
2983
|
* it expires via TTL when configured.
|
|
3009
2984
|
*/
|
|
3010
2985
|
async rotateVault(sub) {
|
|
3011
|
-
const vaultId = (0,
|
|
2986
|
+
const vaultId = (0, import_utils8.randomUUID)();
|
|
3012
2987
|
await this.storage.set(this.indexKey(sub), vaultId, this.credentialSetOpts);
|
|
3013
2988
|
return vaultId;
|
|
3014
2989
|
}
|
|
@@ -3157,19 +3132,19 @@ var SessionCredentialVault = class {
|
|
|
3157
3132
|
}
|
|
3158
3133
|
};
|
|
3159
3134
|
function resolveVaultPepper(logger) {
|
|
3160
|
-
const fromEnv = (0,
|
|
3135
|
+
const fromEnv = (0, import_utils8.getEnv)("VAULT_SECRET") ?? (0, import_utils8.getEnv)("JWT_SECRET");
|
|
3161
3136
|
if (fromEnv && fromEnv.trim().length > 0) return fromEnv;
|
|
3162
3137
|
logger.warn(
|
|
3163
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."
|
|
3164
3139
|
);
|
|
3165
|
-
return (0,
|
|
3140
|
+
return (0, import_utils8.randomUUID)() + (0, import_utils8.randomUUID)();
|
|
3166
3141
|
}
|
|
3167
3142
|
function errMsg(err) {
|
|
3168
3143
|
return err instanceof Error ? err.message : String(err);
|
|
3169
3144
|
}
|
|
3170
3145
|
|
|
3171
3146
|
// libs/auth/src/session/token-storage.factory.ts
|
|
3172
|
-
var
|
|
3147
|
+
var import_utils9 = require("@frontmcp/utils");
|
|
3173
3148
|
function isRedisTokenStorage(config) {
|
|
3174
3149
|
return typeof config === "object" && config !== null && "redis" in config && !!config.redis;
|
|
3175
3150
|
}
|
|
@@ -3181,7 +3156,7 @@ function isPersistentTokenStorage(config) {
|
|
|
3181
3156
|
}
|
|
3182
3157
|
async function createTokenStorageAdapter(config) {
|
|
3183
3158
|
if (config === void 0 || config === "memory") {
|
|
3184
|
-
const adapter = new
|
|
3159
|
+
const adapter = new import_utils9.MemoryStorageAdapter();
|
|
3185
3160
|
await adapter.connect();
|
|
3186
3161
|
return adapter;
|
|
3187
3162
|
}
|
|
@@ -3198,14 +3173,14 @@ async function createTokenStorageAdapter(config) {
|
|
|
3198
3173
|
}
|
|
3199
3174
|
if (isRedisTokenStorage(config)) {
|
|
3200
3175
|
const { host, port, password, db, tls, keyPrefix } = config.redis;
|
|
3201
|
-
const adapter = new
|
|
3176
|
+
const adapter = new import_utils9.RedisStorageAdapter({
|
|
3202
3177
|
config: { host, port, password, db, tls },
|
|
3203
3178
|
keyPrefix: keyPrefix ?? ""
|
|
3204
3179
|
});
|
|
3205
3180
|
await adapter.connect();
|
|
3206
3181
|
return adapter;
|
|
3207
3182
|
}
|
|
3208
|
-
const fallback = new
|
|
3183
|
+
const fallback = new import_utils9.MemoryStorageAdapter();
|
|
3209
3184
|
await fallback.connect();
|
|
3210
3185
|
return fallback;
|
|
3211
3186
|
}
|
|
@@ -3225,7 +3200,7 @@ async function createSessionCredentialVault(options) {
|
|
|
3225
3200
|
}
|
|
3226
3201
|
|
|
3227
3202
|
// libs/auth/src/session/credential-resume-link.ts
|
|
3228
|
-
var
|
|
3203
|
+
var import_utils10 = require("@frontmcp/utils");
|
|
3229
3204
|
var DEFAULT_RESUME_TTL_MS = 6e5;
|
|
3230
3205
|
function signCredentialResumeToken(input, secret) {
|
|
3231
3206
|
const payload = {
|
|
@@ -3234,7 +3209,7 @@ function signCredentialResumeToken(input, secret) {
|
|
|
3234
3209
|
...input.context !== void 0 ? { context: input.context } : {},
|
|
3235
3210
|
exp: Date.now() + (input.ttlMs ?? DEFAULT_RESUME_TTL_MS)
|
|
3236
3211
|
};
|
|
3237
|
-
const signedJson = (0,
|
|
3212
|
+
const signedJson = (0, import_utils10.signData)(payload, { secret });
|
|
3238
3213
|
return Buffer.from(signedJson, "utf8").toString("base64url");
|
|
3239
3214
|
}
|
|
3240
3215
|
function verifyCredentialResumeToken(token, secret, now = Date.now()) {
|
|
@@ -3244,7 +3219,7 @@ function verifyCredentialResumeToken(token, secret, now = Date.now()) {
|
|
|
3244
3219
|
} catch {
|
|
3245
3220
|
return null;
|
|
3246
3221
|
}
|
|
3247
|
-
const payload = (0,
|
|
3222
|
+
const payload = (0, import_utils10.verifyData)(signedJson, { secret });
|
|
3248
3223
|
if (!payload) return null;
|
|
3249
3224
|
if (typeof payload.sub !== "string" || typeof payload.key !== "string" || !Number.isFinite(payload.exp)) {
|
|
3250
3225
|
return null;
|
|
@@ -3263,7 +3238,7 @@ function buildCredentialResumeUrl(basePath, token) {
|
|
|
3263
3238
|
}
|
|
3264
3239
|
|
|
3265
3240
|
// libs/auth/src/session/incremental-auth-ticket.ts
|
|
3266
|
-
var
|
|
3241
|
+
var import_utils11 = require("@frontmcp/utils");
|
|
3267
3242
|
var DEFAULT_INCREMENTAL_TICKET_TTL_MS = 3e5;
|
|
3268
3243
|
function signIncrementalAuthTicket(input, secret) {
|
|
3269
3244
|
const payload = {
|
|
@@ -3271,10 +3246,10 @@ function signIncrementalAuthTicket(input, secret) {
|
|
|
3271
3246
|
appId: input.appId,
|
|
3272
3247
|
...input.toolId !== void 0 ? { toolId: input.toolId } : {},
|
|
3273
3248
|
...input.priorAppIds !== void 0 ? { priorAppIds: input.priorAppIds } : {},
|
|
3274
|
-
jti: (0,
|
|
3249
|
+
jti: (0, import_utils11.randomUUID)(),
|
|
3275
3250
|
exp: Date.now() + (input.ttlMs ?? DEFAULT_INCREMENTAL_TICKET_TTL_MS)
|
|
3276
3251
|
};
|
|
3277
|
-
const signedJson = (0,
|
|
3252
|
+
const signedJson = (0, import_utils11.signData)(payload, { secret });
|
|
3278
3253
|
return Buffer.from(signedJson, "utf8").toString("base64url");
|
|
3279
3254
|
}
|
|
3280
3255
|
function verifyIncrementalAuthTicket(token, secret, now = Date.now()) {
|
|
@@ -3284,7 +3259,7 @@ function verifyIncrementalAuthTicket(token, secret, now = Date.now()) {
|
|
|
3284
3259
|
} catch {
|
|
3285
3260
|
return null;
|
|
3286
3261
|
}
|
|
3287
|
-
const payload = (0,
|
|
3262
|
+
const payload = (0, import_utils11.verifyData)(signedJson, { secret });
|
|
3288
3263
|
if (!payload) return null;
|
|
3289
3264
|
if (typeof payload.sub !== "string" || payload.sub.length === 0) return null;
|
|
3290
3265
|
if (typeof payload.appId !== "string" || payload.appId.length === 0) return null;
|
|
@@ -3464,7 +3439,7 @@ function errMsg2(err) {
|
|
|
3464
3439
|
var SECURE_STORE_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:SECURE_STORE_ACCESSOR");
|
|
3465
3440
|
|
|
3466
3441
|
// libs/auth/src/session/secure-store-accessor.impl.ts
|
|
3467
|
-
var
|
|
3442
|
+
var import_utils12 = require("@frontmcp/utils");
|
|
3468
3443
|
var GLOBAL_NAMESPACE = "global";
|
|
3469
3444
|
var SecureStoreAccessorImpl = class {
|
|
3470
3445
|
backend;
|
|
@@ -3493,12 +3468,12 @@ var SecureStoreAccessorImpl = class {
|
|
|
3493
3468
|
return GLOBAL_NAMESPACE;
|
|
3494
3469
|
case "session": {
|
|
3495
3470
|
const sid = this.resolveSessionId();
|
|
3496
|
-
return sid ? `s:${(0,
|
|
3471
|
+
return sid ? `s:${(0, import_utils12.sha256Hex)(sid).slice(0, 32)}` : void 0;
|
|
3497
3472
|
}
|
|
3498
3473
|
case "user":
|
|
3499
3474
|
default: {
|
|
3500
3475
|
const sub = this.resolveSub();
|
|
3501
|
-
return sub ? `u:${(0,
|
|
3476
|
+
return sub ? `u:${(0, import_utils12.sha256Hex)(sub).slice(0, 32)}` : void 0;
|
|
3502
3477
|
}
|
|
3503
3478
|
}
|
|
3504
3479
|
}
|
|
@@ -3539,7 +3514,7 @@ function errMsg3(err) {
|
|
|
3539
3514
|
}
|
|
3540
3515
|
|
|
3541
3516
|
// libs/auth/src/session/secure-store.factory.ts
|
|
3542
|
-
var
|
|
3517
|
+
var import_utils13 = require("@frontmcp/utils");
|
|
3543
3518
|
function isCustomBackendConfig(config) {
|
|
3544
3519
|
return typeof config === "object" && config !== null && "backend" in config && !!config.backend;
|
|
3545
3520
|
}
|
|
@@ -3588,7 +3563,7 @@ async function createSecureStore(options) {
|
|
|
3588
3563
|
if (storage) {
|
|
3589
3564
|
adapter = storage;
|
|
3590
3565
|
} else if (kind === "memory") {
|
|
3591
|
-
adapter = new
|
|
3566
|
+
adapter = new import_utils13.MemoryStorageAdapter();
|
|
3592
3567
|
await adapter.connect();
|
|
3593
3568
|
} else {
|
|
3594
3569
|
adapter = await createTokenStorageAdapter(toTokenStorageConfig(config));
|
|
@@ -3602,7 +3577,7 @@ async function createSecureStore(options) {
|
|
|
3602
3577
|
}
|
|
3603
3578
|
|
|
3604
3579
|
// libs/auth/src/session/token.vault.ts
|
|
3605
|
-
var
|
|
3580
|
+
var import_utils14 = require("@frontmcp/utils");
|
|
3606
3581
|
var TokenVault = class {
|
|
3607
3582
|
/** Active key used for new encryptions */
|
|
3608
3583
|
active;
|
|
@@ -3631,14 +3606,14 @@ var TokenVault = class {
|
|
|
3631
3606
|
this.keys.set(k.kid, k.key);
|
|
3632
3607
|
}
|
|
3633
3608
|
async encrypt(plaintext, opts) {
|
|
3634
|
-
const iv = (0,
|
|
3635
|
-
const { ciphertext, tag } = await (0,
|
|
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);
|
|
3636
3611
|
return {
|
|
3637
3612
|
alg: "A256GCM",
|
|
3638
3613
|
kid: this.active.kid,
|
|
3639
|
-
iv: (0,
|
|
3640
|
-
tag: (0,
|
|
3641
|
-
data: (0,
|
|
3614
|
+
iv: (0, import_utils14.base64urlEncode)(iv),
|
|
3615
|
+
tag: (0, import_utils14.base64urlEncode)(tag),
|
|
3616
|
+
data: (0, import_utils14.base64urlEncode)(ciphertext),
|
|
3642
3617
|
exp: opts?.exp,
|
|
3643
3618
|
meta: opts?.meta
|
|
3644
3619
|
};
|
|
@@ -3652,16 +3627,16 @@ var TokenVault = class {
|
|
|
3652
3627
|
}
|
|
3653
3628
|
const key = this.keys.get(blob.kid);
|
|
3654
3629
|
if (!key) throw new Error(`vault_unknown_kid:${blob.kid}`);
|
|
3655
|
-
const iv = (0,
|
|
3656
|
-
const tag = (0,
|
|
3657
|
-
const data = (0,
|
|
3658
|
-
const plaintext = await (0,
|
|
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);
|
|
3659
3634
|
return new TextDecoder().decode(plaintext);
|
|
3660
3635
|
}
|
|
3661
3636
|
};
|
|
3662
3637
|
|
|
3663
3638
|
// libs/auth/src/session/index.ts
|
|
3664
|
-
var
|
|
3639
|
+
var import_utils34 = require("@frontmcp/utils");
|
|
3665
3640
|
|
|
3666
3641
|
// libs/auth/src/session/transport-session.types.ts
|
|
3667
3642
|
var import_lazy_zod4 = require("@frontmcp/lazy-zod");
|
|
@@ -3757,10 +3732,10 @@ var redisConfigSchema = import_lazy_zod4.z.object({
|
|
|
3757
3732
|
});
|
|
3758
3733
|
|
|
3759
3734
|
// libs/auth/src/session/session-crypto.ts
|
|
3760
|
-
var
|
|
3735
|
+
var import_utils16 = require("@frontmcp/utils");
|
|
3761
3736
|
|
|
3762
3737
|
// libs/auth/src/errors/auth-internal.error.ts
|
|
3763
|
-
var
|
|
3738
|
+
var import_utils15 = require("@frontmcp/utils");
|
|
3764
3739
|
var AuthInternalError = class extends Error {
|
|
3765
3740
|
/**
|
|
3766
3741
|
* Unique error ID for tracking in logs.
|
|
@@ -3782,7 +3757,7 @@ var AuthInternalError = class extends Error {
|
|
|
3782
3757
|
super(message);
|
|
3783
3758
|
this.name = this.constructor.name;
|
|
3784
3759
|
this.code = code;
|
|
3785
|
-
this.errorId = `err_${(0,
|
|
3760
|
+
this.errorId = `err_${(0, import_utils15.bytesToHex)((0, import_utils15.randomBytes)(8))}`;
|
|
3786
3761
|
Error.captureStackTrace(this, this.constructor);
|
|
3787
3762
|
}
|
|
3788
3763
|
/**
|
|
@@ -3842,6 +3817,22 @@ var SessionSecretRequiredError = class extends AuthInternalError {
|
|
|
3842
3817
|
super(`Session secret is required for ${component}`, "SESSION_SECRET_REQUIRED");
|
|
3843
3818
|
}
|
|
3844
3819
|
};
|
|
3820
|
+
var JwtSecretRequiredError = class extends AuthInternalError {
|
|
3821
|
+
constructor(mode) {
|
|
3822
|
+
super(
|
|
3823
|
+
`JWT_SECRET is required in production for auth.mode "${mode}". Without it the server signs tokens with a random per-process secret, so every restart invalidates outstanding tokens and any second instance or isolate rejects tokens the first one minted.`,
|
|
3824
|
+
"JWT_SECRET_REQUIRED"
|
|
3825
|
+
);
|
|
3826
|
+
}
|
|
3827
|
+
};
|
|
3828
|
+
var JwtSecretWeakError = class extends AuthInternalError {
|
|
3829
|
+
constructor(byteLength) {
|
|
3830
|
+
super(
|
|
3831
|
+
`JWT_SECRET is ${byteLength} bytes; HS256 requires at least 32 (RFC 7518 \xA73.2). A shorter secret is guessable, and whoever guesses it can forge tokens for this server. Generate one with \`openssl rand -hex 32\`.`,
|
|
3832
|
+
"JWT_SECRET_INVALID"
|
|
3833
|
+
);
|
|
3834
|
+
}
|
|
3835
|
+
};
|
|
3845
3836
|
var CredentialProviderAlreadyRegisteredError = class extends AuthInternalError {
|
|
3846
3837
|
constructor(name) {
|
|
3847
3838
|
super(`Credential provider "${name}" is already registered`, "CREDENTIAL_PROVIDER_ALREADY_REGISTERED");
|
|
@@ -3905,9 +3896,9 @@ var AuthFlowError = class extends AuthInternalError {
|
|
|
3905
3896
|
|
|
3906
3897
|
// libs/auth/src/session/session-crypto.ts
|
|
3907
3898
|
function getSigningSecret(config) {
|
|
3908
|
-
const secret = config?.secret || (0,
|
|
3899
|
+
const secret = config?.secret || (0, import_utils16.getEnv)("MCP_SESSION_SECRET");
|
|
3909
3900
|
if (!secret) {
|
|
3910
|
-
if ((0,
|
|
3901
|
+
if ((0, import_utils16.isProduction)()) {
|
|
3911
3902
|
throw new SessionSecretRequiredError("session signing");
|
|
3912
3903
|
}
|
|
3913
3904
|
console.warn("[SessionCrypto] MCP_SESSION_SECRET not set. Using insecure default for development only.");
|
|
@@ -3919,13 +3910,13 @@ function resolveConfig(config) {
|
|
|
3919
3910
|
return { secret: getSigningSecret(config) };
|
|
3920
3911
|
}
|
|
3921
3912
|
function signSession(session, config) {
|
|
3922
|
-
return (0,
|
|
3913
|
+
return (0, import_utils16.signData)(session, resolveConfig(config));
|
|
3923
3914
|
}
|
|
3924
3915
|
function verifySession(signedData, config) {
|
|
3925
|
-
return (0,
|
|
3916
|
+
return (0, import_utils16.verifyData)(signedData, resolveConfig(config));
|
|
3926
3917
|
}
|
|
3927
3918
|
function verifyOrParseSession(data, config) {
|
|
3928
|
-
return (0,
|
|
3919
|
+
return (0, import_utils16.verifyOrParseData)(data, resolveConfig(config));
|
|
3929
3920
|
}
|
|
3930
3921
|
|
|
3931
3922
|
// libs/auth/src/session/session-rate-limiter.ts
|
|
@@ -4052,7 +4043,7 @@ var SessionRateLimiter = class {
|
|
|
4052
4043
|
var defaultSessionRateLimiter = new SessionRateLimiter();
|
|
4053
4044
|
|
|
4054
4045
|
// libs/auth/src/session/session.transport.ts
|
|
4055
|
-
var
|
|
4046
|
+
var import_utils17 = require("@frontmcp/utils");
|
|
4056
4047
|
var TransportIdGenerator = class {
|
|
4057
4048
|
/**
|
|
4058
4049
|
* Create a transport session ID.
|
|
@@ -4061,7 +4052,7 @@ var TransportIdGenerator = class {
|
|
|
4061
4052
|
* @returns A transport session ID (UUID without dashes)
|
|
4062
4053
|
*/
|
|
4063
4054
|
static createId() {
|
|
4064
|
-
return (0,
|
|
4055
|
+
return (0, import_utils17.randomUUID)().replace(/-/g, "");
|
|
4065
4056
|
}
|
|
4066
4057
|
};
|
|
4067
4058
|
|
|
@@ -4110,7 +4101,7 @@ var TinyTtlCache = class {
|
|
|
4110
4101
|
};
|
|
4111
4102
|
|
|
4112
4103
|
// libs/auth/src/session/utils/auth-token.utils.ts
|
|
4113
|
-
var
|
|
4104
|
+
var import_utils18 = require("@frontmcp/utils");
|
|
4114
4105
|
function isJwt(token) {
|
|
4115
4106
|
if (!token) return false;
|
|
4116
4107
|
return token.split(".").length === 3;
|
|
@@ -4120,7 +4111,7 @@ function getTokenSignatureFingerprint(token) {
|
|
|
4120
4111
|
const sig = token.split(".")[2];
|
|
4121
4112
|
if (sig) return sig;
|
|
4122
4113
|
}
|
|
4123
|
-
return (0,
|
|
4114
|
+
return (0, import_utils18.sha256Base64url)(token);
|
|
4124
4115
|
}
|
|
4125
4116
|
function extractClaimValue(claims, key, validator) {
|
|
4126
4117
|
const value = claims[key];
|
|
@@ -4152,26 +4143,26 @@ function extractBearerToken(header) {
|
|
|
4152
4143
|
}
|
|
4153
4144
|
|
|
4154
4145
|
// libs/auth/src/session/utils/session-crypto.utils.ts
|
|
4155
|
-
var
|
|
4146
|
+
var import_utils19 = require("@frontmcp/utils");
|
|
4156
4147
|
var cachedKey = null;
|
|
4157
4148
|
function getKey() {
|
|
4158
4149
|
if (cachedKey) return cachedKey;
|
|
4159
|
-
const secret = (0,
|
|
4150
|
+
const secret = (0, import_utils19.getEnv)("MCP_SESSION_SECRET");
|
|
4160
4151
|
if (!secret) {
|
|
4161
|
-
if ((0,
|
|
4152
|
+
if ((0, import_utils19.isProduction)()) {
|
|
4162
4153
|
throw new SessionSecretRequiredError("session ID encryption");
|
|
4163
4154
|
}
|
|
4164
4155
|
console.warn(
|
|
4165
4156
|
"[SessionIdUtils] Using machine ID as session encryption secret - NOT SECURE FOR PRODUCTION. Set MCP_SESSION_SECRET environment variable for secure session encryption."
|
|
4166
4157
|
);
|
|
4167
4158
|
}
|
|
4168
|
-
const base = secret || (0,
|
|
4169
|
-
cachedKey = (0,
|
|
4159
|
+
const base = secret || (0, import_utils19.getMachineId)();
|
|
4160
|
+
cachedKey = (0, import_utils19.sha256)(new TextEncoder().encode(base));
|
|
4170
4161
|
return cachedKey;
|
|
4171
4162
|
}
|
|
4172
4163
|
function encryptJson(obj) {
|
|
4173
4164
|
const key = getKey();
|
|
4174
|
-
const encrypted = (0,
|
|
4165
|
+
const encrypted = (0, import_utils19.encryptValue)(obj, key);
|
|
4175
4166
|
return `${encrypted.iv}.${encrypted.tag}.${encrypted.data}`;
|
|
4176
4167
|
}
|
|
4177
4168
|
function decryptSessionJson(sessionId) {
|
|
@@ -4180,7 +4171,7 @@ function decryptSessionJson(sessionId) {
|
|
|
4180
4171
|
const [ivB64, tagB64, ctB64] = parts;
|
|
4181
4172
|
if (!ivB64 || !tagB64 || !ctB64) return null;
|
|
4182
4173
|
const key = getKey();
|
|
4183
|
-
return (0,
|
|
4174
|
+
return (0, import_utils19.decryptValue)({ alg: "A256GCM", iv: ivB64, tag: tagB64, data: ctB64 }, key);
|
|
4184
4175
|
}
|
|
4185
4176
|
function safeDecrypt(sessionId) {
|
|
4186
4177
|
try {
|
|
@@ -4194,11 +4185,11 @@ function resetCachedKey() {
|
|
|
4194
4185
|
}
|
|
4195
4186
|
|
|
4196
4187
|
// libs/auth/src/session/storage/index.ts
|
|
4197
|
-
var import_utils22 = require("@frontmcp/utils");
|
|
4198
4188
|
var import_utils23 = require("@frontmcp/utils");
|
|
4189
|
+
var import_utils24 = require("@frontmcp/utils");
|
|
4199
4190
|
|
|
4200
4191
|
// libs/auth/src/session/storage/storage-token-store.ts
|
|
4201
|
-
var
|
|
4192
|
+
var import_utils20 = require("@frontmcp/utils");
|
|
4202
4193
|
var StorageTokenStore = class {
|
|
4203
4194
|
storage;
|
|
4204
4195
|
namespace;
|
|
@@ -4210,13 +4201,13 @@ var StorageTokenStore = class {
|
|
|
4210
4201
|
this.defaultTtlSeconds = options.defaultTtlSeconds;
|
|
4211
4202
|
this.storageIsNamespaced = "namespace" in storage && typeof storage.namespace === "function";
|
|
4212
4203
|
const namespacedStorage = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
|
|
4213
|
-
this.storage = new
|
|
4204
|
+
this.storage = new import_utils20.TypedStorage(namespacedStorage);
|
|
4214
4205
|
}
|
|
4215
4206
|
/**
|
|
4216
4207
|
* Allocate a new unique ID for a token record.
|
|
4217
4208
|
*/
|
|
4218
4209
|
allocId() {
|
|
4219
|
-
return (0,
|
|
4210
|
+
return (0, import_utils20.randomUUID)();
|
|
4220
4211
|
}
|
|
4221
4212
|
/**
|
|
4222
4213
|
* Store an encrypted token blob.
|
|
@@ -4279,7 +4270,7 @@ var StorageTokenStore = class {
|
|
|
4279
4270
|
};
|
|
4280
4271
|
|
|
4281
4272
|
// libs/auth/src/session/storage/storage-authorization-vault.ts
|
|
4282
|
-
var
|
|
4273
|
+
var import_utils21 = require("@frontmcp/utils");
|
|
4283
4274
|
var StorageAuthorizationVault = class {
|
|
4284
4275
|
storage;
|
|
4285
4276
|
namespace;
|
|
@@ -4288,7 +4279,7 @@ var StorageAuthorizationVault = class {
|
|
|
4288
4279
|
this.namespace = options.namespace ?? "vault";
|
|
4289
4280
|
this.pendingAuthTtlMs = options.pendingAuthTtlMs ?? 10 * 60 * 1e3;
|
|
4290
4281
|
const namespacedStorage = this.isNamespacedStorage(storage) ? storage.namespace(this.namespace) : storage;
|
|
4291
|
-
this.storage = new
|
|
4282
|
+
this.storage = new import_utils21.TypedStorage(namespacedStorage, {
|
|
4292
4283
|
schema: options.validateOnRead ? authorizationVaultEntrySchema : void 0,
|
|
4293
4284
|
throwOnInvalid: false
|
|
4294
4285
|
});
|
|
@@ -4299,7 +4290,7 @@ var StorageAuthorizationVault = class {
|
|
|
4299
4290
|
async create(params) {
|
|
4300
4291
|
const now = Date.now();
|
|
4301
4292
|
const entry = {
|
|
4302
|
-
id: (0,
|
|
4293
|
+
id: (0, import_utils21.randomUUID)(),
|
|
4303
4294
|
userSub: params.userSub,
|
|
4304
4295
|
userEmail: params.userEmail,
|
|
4305
4296
|
userName: params.userName,
|
|
@@ -4373,7 +4364,7 @@ var StorageAuthorizationVault = class {
|
|
|
4373
4364
|
}
|
|
4374
4365
|
const now = Date.now();
|
|
4375
4366
|
const pendingAuth = {
|
|
4376
|
-
id: (0,
|
|
4367
|
+
id: (0, import_utils21.randomUUID)(),
|
|
4377
4368
|
appId: params.appId,
|
|
4378
4369
|
toolId: params.toolId,
|
|
4379
4370
|
authUrl: params.authUrl,
|
|
@@ -4577,11 +4568,11 @@ var StorageAuthorizationVault = class {
|
|
|
4577
4568
|
};
|
|
4578
4569
|
|
|
4579
4570
|
// libs/auth/src/session/storage/in-memory-authorization-vault.ts
|
|
4580
|
-
var
|
|
4571
|
+
var import_utils22 = require("@frontmcp/utils");
|
|
4581
4572
|
var InMemoryAuthorizationVault = class extends StorageAuthorizationVault {
|
|
4582
4573
|
memoryAdapter;
|
|
4583
4574
|
constructor(options = {}) {
|
|
4584
|
-
const memoryAdapter = new
|
|
4575
|
+
const memoryAdapter = new import_utils22.MemoryStorageAdapter();
|
|
4585
4576
|
super(memoryAdapter, {
|
|
4586
4577
|
namespace: options.namespace ?? "vault",
|
|
4587
4578
|
pendingAuthTtlMs: options.pendingAuthTtlMs
|
|
@@ -4602,7 +4593,7 @@ var InMemoryAuthorizationVault = class extends StorageAuthorizationVault {
|
|
|
4602
4593
|
};
|
|
4603
4594
|
|
|
4604
4595
|
// libs/auth/src/session/redis-session.store.ts
|
|
4605
|
-
var
|
|
4596
|
+
var import_utils25 = require("@frontmcp/utils");
|
|
4606
4597
|
var RedisSessionStore = class {
|
|
4607
4598
|
storage;
|
|
4608
4599
|
keyPrefix;
|
|
@@ -4624,14 +4615,14 @@ var RedisSessionStore = class {
|
|
|
4624
4615
|
});
|
|
4625
4616
|
}
|
|
4626
4617
|
if ("redis" in config && config.redis) {
|
|
4627
|
-
this.storage = new
|
|
4618
|
+
this.storage = new import_utils25.RedisStorageAdapter({
|
|
4628
4619
|
client: config.redis,
|
|
4629
4620
|
keyPrefix: this.keyPrefix
|
|
4630
4621
|
});
|
|
4631
4622
|
this.externalInstance = true;
|
|
4632
4623
|
} else {
|
|
4633
4624
|
const redisConfig = config;
|
|
4634
|
-
this.storage = new
|
|
4625
|
+
this.storage = new import_utils25.RedisStorageAdapter({
|
|
4635
4626
|
config: {
|
|
4636
4627
|
host: redisConfig.host,
|
|
4637
4628
|
port: redisConfig.port ?? 6379,
|
|
@@ -4813,7 +4804,7 @@ var RedisSessionStore = class {
|
|
|
4813
4804
|
* Allocate a new session ID
|
|
4814
4805
|
*/
|
|
4815
4806
|
allocId() {
|
|
4816
|
-
return (0,
|
|
4807
|
+
return (0, import_utils25.randomUUID)();
|
|
4817
4808
|
}
|
|
4818
4809
|
/**
|
|
4819
4810
|
* Disconnect from Redis (only if we created the connection)
|
|
@@ -4849,7 +4840,7 @@ var RedisSessionStore = class {
|
|
|
4849
4840
|
};
|
|
4850
4841
|
|
|
4851
4842
|
// libs/auth/src/session/vercel-kv-session.store.ts
|
|
4852
|
-
var
|
|
4843
|
+
var import_utils26 = require("@frontmcp/utils");
|
|
4853
4844
|
var VercelKvSessionStore = class {
|
|
4854
4845
|
storage;
|
|
4855
4846
|
keyPrefix;
|
|
@@ -4869,7 +4860,7 @@ var VercelKvSessionStore = class {
|
|
|
4869
4860
|
maxRequests: this.security.rateLimiting?.maxRequests
|
|
4870
4861
|
});
|
|
4871
4862
|
}
|
|
4872
|
-
this.storage = new
|
|
4863
|
+
this.storage = new import_utils26.VercelKvStorageAdapter({
|
|
4873
4864
|
url: config.url,
|
|
4874
4865
|
token: config.token,
|
|
4875
4866
|
keyPrefix: this.keyPrefix
|
|
@@ -5043,7 +5034,7 @@ var VercelKvSessionStore = class {
|
|
|
5043
5034
|
* Allocate a new session ID
|
|
5044
5035
|
*/
|
|
5045
5036
|
allocId() {
|
|
5046
|
-
return (0,
|
|
5037
|
+
return (0, import_utils26.randomUUID)();
|
|
5047
5038
|
}
|
|
5048
5039
|
/**
|
|
5049
5040
|
* Disconnect from Vercel KV
|
|
@@ -5072,7 +5063,7 @@ var VercelKvSessionStore = class {
|
|
|
5072
5063
|
};
|
|
5073
5064
|
|
|
5074
5065
|
// libs/auth/src/session/orchestrated-token.store.ts
|
|
5075
|
-
var
|
|
5066
|
+
var import_utils27 = require("@frontmcp/utils");
|
|
5076
5067
|
var InMemoryOrchestratedTokenStore = class {
|
|
5077
5068
|
/** Token storage: Map<compositeKey, ProviderTokenRecord> */
|
|
5078
5069
|
tokens = /* @__PURE__ */ new Map();
|
|
@@ -5114,7 +5105,7 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
5114
5105
|
}
|
|
5115
5106
|
const info = new TextEncoder().encode(`orchestrated-token:${compositeKey}`);
|
|
5116
5107
|
const salt = new TextEncoder().encode("frontmcp-token-store");
|
|
5117
|
-
const derivedKey = (0,
|
|
5108
|
+
const derivedKey = (0, import_utils27.hkdfSha256)(this.encryptionKey, salt, info, 32);
|
|
5118
5109
|
this.derivedKeys.set(compositeKey, derivedKey);
|
|
5119
5110
|
return derivedKey;
|
|
5120
5111
|
}
|
|
@@ -5124,8 +5115,8 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
5124
5115
|
async encryptRecord(compositeKey, record) {
|
|
5125
5116
|
const key = await this.deriveKeyForRecord(compositeKey);
|
|
5126
5117
|
const plaintext = JSON.stringify(record);
|
|
5127
|
-
const iv = (0,
|
|
5128
|
-
const { ciphertext, tag } = (0,
|
|
5118
|
+
const iv = (0, import_utils27.randomBytes)(12);
|
|
5119
|
+
const { ciphertext, tag } = (0, import_utils27.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
|
|
5129
5120
|
return JSON.stringify({
|
|
5130
5121
|
iv: Buffer.from(iv).toString("base64url"),
|
|
5131
5122
|
tag: Buffer.from(tag).toString("base64url"),
|
|
@@ -5141,7 +5132,7 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
5141
5132
|
const ivBytes = Buffer.from(iv, "base64url");
|
|
5142
5133
|
const tagBytes = Buffer.from(tag, "base64url");
|
|
5143
5134
|
const ciphertextBytes = Buffer.from(data, "base64url");
|
|
5144
|
-
const plaintext = (0,
|
|
5135
|
+
const plaintext = (0, import_utils27.decryptAesGcm)(key, ciphertextBytes, ivBytes, tagBytes);
|
|
5145
5136
|
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
5146
5137
|
}
|
|
5147
5138
|
/**
|
|
@@ -5343,7 +5334,7 @@ var InMemoryOrchestratedTokenStore = class {
|
|
|
5343
5334
|
};
|
|
5344
5335
|
|
|
5345
5336
|
// libs/auth/src/session/orchestrated-token.crypto.ts
|
|
5346
|
-
var
|
|
5337
|
+
var import_utils28 = require("@frontmcp/utils");
|
|
5347
5338
|
var HKDF_SALT = new TextEncoder().encode("frontmcp-token-store");
|
|
5348
5339
|
function deriveKeyForRecord(masterKey, compositeKey, cache) {
|
|
5349
5340
|
const cached = cache.get(compositeKey);
|
|
@@ -5351,14 +5342,14 @@ function deriveKeyForRecord(masterKey, compositeKey, cache) {
|
|
|
5351
5342
|
return cached;
|
|
5352
5343
|
}
|
|
5353
5344
|
const info = new TextEncoder().encode(`orchestrated-token:${compositeKey}`);
|
|
5354
|
-
const derived = (0,
|
|
5345
|
+
const derived = (0, import_utils28.hkdfSha256)(masterKey, HKDF_SALT, info, 32);
|
|
5355
5346
|
cache.set(compositeKey, derived);
|
|
5356
5347
|
return derived;
|
|
5357
5348
|
}
|
|
5358
5349
|
function encryptRecord(key, record) {
|
|
5359
5350
|
const plaintext = JSON.stringify(record);
|
|
5360
|
-
const iv = (0,
|
|
5361
|
-
const { ciphertext, tag } = (0,
|
|
5351
|
+
const iv = (0, import_utils28.randomBytes)(12);
|
|
5352
|
+
const { ciphertext, tag } = (0, import_utils28.encryptAesGcm)(key, new TextEncoder().encode(plaintext), iv);
|
|
5362
5353
|
return JSON.stringify({
|
|
5363
5354
|
iv: Buffer.from(iv).toString("base64url"),
|
|
5364
5355
|
tag: Buffer.from(tag).toString("base64url"),
|
|
@@ -5370,7 +5361,7 @@ function decryptRecord(key, encrypted) {
|
|
|
5370
5361
|
const ivBytes = Buffer.from(iv, "base64url");
|
|
5371
5362
|
const tagBytes = Buffer.from(tag, "base64url");
|
|
5372
5363
|
const ciphertextBytes = Buffer.from(data, "base64url");
|
|
5373
|
-
const plaintext = (0,
|
|
5364
|
+
const plaintext = (0, import_utils28.decryptAesGcm)(key, ciphertextBytes, ivBytes, tagBytes);
|
|
5374
5365
|
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
5375
5366
|
}
|
|
5376
5367
|
|
|
@@ -5549,7 +5540,7 @@ var StorageOrchestratedTokenStore = class {
|
|
|
5549
5540
|
};
|
|
5550
5541
|
|
|
5551
5542
|
// libs/auth/src/session/federated-auth.session.ts
|
|
5552
|
-
var
|
|
5543
|
+
var import_utils29 = require("@frontmcp/utils");
|
|
5553
5544
|
function toSessionRecord(session) {
|
|
5554
5545
|
return {
|
|
5555
5546
|
...session,
|
|
@@ -5624,7 +5615,7 @@ var InMemoryFederatedAuthSessionStore = class {
|
|
|
5624
5615
|
createSession(params) {
|
|
5625
5616
|
const now = Date.now();
|
|
5626
5617
|
return {
|
|
5627
|
-
id: (0,
|
|
5618
|
+
id: (0, import_utils29.randomUUID)(),
|
|
5628
5619
|
pendingAuthId: params.pendingAuthId,
|
|
5629
5620
|
clientId: params.clientId,
|
|
5630
5621
|
redirectUri: params.redirectUri,
|
|
@@ -5656,7 +5647,7 @@ var InMemoryFederatedAuthSessionStore = class {
|
|
|
5656
5647
|
function createFederatedAuthSession(params, ttlMs = 15 * 60 * 1e3) {
|
|
5657
5648
|
const now = Date.now();
|
|
5658
5649
|
return {
|
|
5659
|
-
id: (0,
|
|
5650
|
+
id: (0, import_utils29.randomUUID)(),
|
|
5660
5651
|
pendingAuthId: params.pendingAuthId,
|
|
5661
5652
|
clientId: params.clientId,
|
|
5662
5653
|
redirectUri: params.redirectUri,
|
|
@@ -5713,7 +5704,7 @@ function startNextProvider(session, pkce, state) {
|
|
|
5713
5704
|
}
|
|
5714
5705
|
|
|
5715
5706
|
// libs/auth/src/session/storage-federated-auth.session.ts
|
|
5716
|
-
var
|
|
5707
|
+
var import_utils30 = require("@frontmcp/utils");
|
|
5717
5708
|
var StorageFederatedAuthSessionStore = class {
|
|
5718
5709
|
storage;
|
|
5719
5710
|
namespace;
|
|
@@ -5722,7 +5713,7 @@ var StorageFederatedAuthSessionStore = class {
|
|
|
5722
5713
|
this.namespace = options.namespace ?? "fed";
|
|
5723
5714
|
this.storageIsNamespaced = this.isNamespacedStorage(storage);
|
|
5724
5715
|
const namespacedStorage = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
|
|
5725
|
-
this.storage = new
|
|
5716
|
+
this.storage = new import_utils30.TypedStorage(namespacedStorage);
|
|
5726
5717
|
}
|
|
5727
5718
|
async store(session) {
|
|
5728
5719
|
await this.put(session);
|
|
@@ -5793,7 +5784,7 @@ var InMemoryConsentStore = class {
|
|
|
5793
5784
|
};
|
|
5794
5785
|
|
|
5795
5786
|
// libs/auth/src/session/storage-consent.store.ts
|
|
5796
|
-
var
|
|
5787
|
+
var import_utils31 = require("@frontmcp/utils");
|
|
5797
5788
|
var StorageConsentStore = class {
|
|
5798
5789
|
storage;
|
|
5799
5790
|
namespace;
|
|
@@ -5802,7 +5793,7 @@ var StorageConsentStore = class {
|
|
|
5802
5793
|
this.namespace = options.namespace ?? "remembered-consent";
|
|
5803
5794
|
this.storageIsNamespaced = this.isNamespacedStorage(storage);
|
|
5804
5795
|
const namespacedStorage = this.storageIsNamespaced ? storage.namespace(this.namespace) : storage;
|
|
5805
|
-
this.storage = new
|
|
5796
|
+
this.storage = new import_utils31.TypedStorage(namespacedStorage);
|
|
5806
5797
|
}
|
|
5807
5798
|
async get(userSub, clientId) {
|
|
5808
5799
|
return this.storage.get(this.key(userSub, clientId));
|
|
@@ -5824,7 +5815,7 @@ var StorageConsentStore = class {
|
|
|
5824
5815
|
|
|
5825
5816
|
// libs/auth/src/session/encrypted-authorization-vault.ts
|
|
5826
5817
|
var import_lazy_zod5 = require("@frontmcp/lazy-zod");
|
|
5827
|
-
var
|
|
5818
|
+
var import_utils32 = require("@frontmcp/utils");
|
|
5828
5819
|
var redisVaultEntrySchema = import_lazy_zod5.z.object({
|
|
5829
5820
|
/** Vault ID */
|
|
5830
5821
|
id: import_lazy_zod5.z.string(),
|
|
@@ -5849,7 +5840,7 @@ var redisVaultEntrySchema = import_lazy_zod5.z.object({
|
|
|
5849
5840
|
/** Encrypted sensitive data blob */
|
|
5850
5841
|
encrypted: encryptedDataSchema
|
|
5851
5842
|
});
|
|
5852
|
-
var encryptionContextStorage = new
|
|
5843
|
+
var encryptionContextStorage = new import_utils32.AsyncLocalStorage();
|
|
5853
5844
|
var EncryptedRedisVault = class {
|
|
5854
5845
|
constructor(redis, encryption, namespace = "vault:") {
|
|
5855
5846
|
this.redis = redis;
|
|
@@ -5985,7 +5976,7 @@ var EncryptedRedisVault = class {
|
|
|
5985
5976
|
async create(params) {
|
|
5986
5977
|
const now = Date.now();
|
|
5987
5978
|
const entry = {
|
|
5988
|
-
id: (0,
|
|
5979
|
+
id: (0, import_utils32.randomUUID)(),
|
|
5989
5980
|
userSub: params.userSub,
|
|
5990
5981
|
userEmail: params.userEmail,
|
|
5991
5982
|
userName: params.userName,
|
|
@@ -6044,7 +6035,7 @@ var EncryptedRedisVault = class {
|
|
|
6044
6035
|
}
|
|
6045
6036
|
const now = Date.now();
|
|
6046
6037
|
const pendingAuth = {
|
|
6047
|
-
id: (0,
|
|
6038
|
+
id: (0, import_utils32.randomUUID)(),
|
|
6048
6039
|
appId: params.appId,
|
|
6049
6040
|
toolId: params.toolId,
|
|
6050
6041
|
authUrl: params.authUrl,
|
|
@@ -6222,7 +6213,7 @@ function createEncryptedVault(redis, config = {}) {
|
|
|
6222
6213
|
}
|
|
6223
6214
|
|
|
6224
6215
|
// libs/auth/src/session/token.refresh.ts
|
|
6225
|
-
var
|
|
6216
|
+
var import_utils33 = require("@frontmcp/utils");
|
|
6226
6217
|
function toEpochSeconds(exp) {
|
|
6227
6218
|
if (exp == null) return void 0;
|
|
6228
6219
|
if (exp instanceof Date) return Math.floor(exp.getTime() / 1e3);
|
|
@@ -6244,7 +6235,7 @@ function tryJwtExp(token) {
|
|
|
6244
6235
|
const parts = token.split(".");
|
|
6245
6236
|
if (parts.length < 2) return void 0;
|
|
6246
6237
|
try {
|
|
6247
|
-
const json = JSON.parse(new TextDecoder().decode((0,
|
|
6238
|
+
const json = JSON.parse(new TextDecoder().decode((0, import_utils33.base64urlDecode)(parts[1])));
|
|
6248
6239
|
const e = json?.exp;
|
|
6249
6240
|
return typeof e === "number" ? toEpochSeconds(e) : void 0;
|
|
6250
6241
|
} catch {
|
|
@@ -6307,7 +6298,7 @@ var progressiveAuthStateSchema = import_lazy_zod6.z.object({
|
|
|
6307
6298
|
});
|
|
6308
6299
|
|
|
6309
6300
|
// libs/auth/src/authorization/authorization.class.ts
|
|
6310
|
-
var
|
|
6301
|
+
var import_utils36 = require("@frontmcp/utils");
|
|
6311
6302
|
var AuthorizationBase = class _AuthorizationBase {
|
|
6312
6303
|
id;
|
|
6313
6304
|
isAnonymous;
|
|
@@ -6355,14 +6346,14 @@ var AuthorizationBase = class _AuthorizationBase {
|
|
|
6355
6346
|
* @param fingerprint - Optional client fingerprint for tracking
|
|
6356
6347
|
*/
|
|
6357
6348
|
createTransportSession(protocol, fingerprint) {
|
|
6358
|
-
const sessionId = (0,
|
|
6349
|
+
const sessionId = (0, import_utils36.randomUUID)();
|
|
6359
6350
|
const session = {
|
|
6360
6351
|
id: sessionId,
|
|
6361
6352
|
authorizationId: this.id,
|
|
6362
6353
|
protocol,
|
|
6363
6354
|
createdAt: Date.now(),
|
|
6364
6355
|
expiresAt: this.expiresAt,
|
|
6365
|
-
nodeId: (0,
|
|
6356
|
+
nodeId: (0, import_utils36.getMachineId)(),
|
|
6366
6357
|
clientFingerprint: fingerprint
|
|
6367
6358
|
};
|
|
6368
6359
|
this.#sessions.set(session.id, session);
|
|
@@ -6503,7 +6494,7 @@ var AuthorizationBase = class _AuthorizationBase {
|
|
|
6503
6494
|
*/
|
|
6504
6495
|
static isJwtHeader(segment) {
|
|
6505
6496
|
try {
|
|
6506
|
-
const bytes = (0,
|
|
6497
|
+
const bytes = (0, import_utils36.base64urlDecode)(segment);
|
|
6507
6498
|
const text = new TextDecoder().decode(bytes);
|
|
6508
6499
|
const parsed = JSON.parse(text);
|
|
6509
6500
|
return typeof parsed === "object" && parsed !== null && typeof parsed.alg === "string";
|
|
@@ -6555,7 +6546,7 @@ var AuthorizationBase = class _AuthorizationBase {
|
|
|
6555
6546
|
};
|
|
6556
6547
|
|
|
6557
6548
|
// libs/auth/src/authorization/public.authorization.ts
|
|
6558
|
-
var
|
|
6549
|
+
var import_utils37 = require("@frontmcp/utils");
|
|
6559
6550
|
var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
|
|
6560
6551
|
mode = "public";
|
|
6561
6552
|
/**
|
|
@@ -6591,7 +6582,7 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
|
|
|
6591
6582
|
allowedTools = "all",
|
|
6592
6583
|
allowedPrompts = "all"
|
|
6593
6584
|
} = ctx;
|
|
6594
|
-
const uuid = (0,
|
|
6585
|
+
const uuid = (0, import_utils37.randomUUID)();
|
|
6595
6586
|
const sub = `${prefix}:${uuid}`;
|
|
6596
6587
|
const user = {
|
|
6597
6588
|
sub,
|
|
@@ -6675,7 +6666,7 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
|
|
|
6675
6666
|
};
|
|
6676
6667
|
|
|
6677
6668
|
// libs/auth/src/authorization/transparent.authorization.ts
|
|
6678
|
-
var
|
|
6669
|
+
var import_utils38 = require("@frontmcp/utils");
|
|
6679
6670
|
var TransparentAuthorization = class _TransparentAuthorization extends AuthorizationBase {
|
|
6680
6671
|
mode = "transparent";
|
|
6681
6672
|
/**
|
|
@@ -6775,7 +6766,7 @@ var TransparentAuthorization = class _TransparentAuthorization extends Authoriza
|
|
|
6775
6766
|
static generateAuthorizationId(token) {
|
|
6776
6767
|
const parts = token.split(".");
|
|
6777
6768
|
const signature = parts[2] || token;
|
|
6778
|
-
return (0,
|
|
6769
|
+
return (0, import_utils38.sha256Hex)(signature).substring(0, 16);
|
|
6779
6770
|
}
|
|
6780
6771
|
/**
|
|
6781
6772
|
* Get the issuer from the token claims
|
|
@@ -6801,11 +6792,11 @@ var TransparentAuthorization = class _TransparentAuthorization extends Authoriza
|
|
|
6801
6792
|
};
|
|
6802
6793
|
|
|
6803
6794
|
// libs/auth/src/utils/authorization-id.utils.ts
|
|
6804
|
-
var
|
|
6795
|
+
var import_utils39 = require("@frontmcp/utils");
|
|
6805
6796
|
function deriveAuthorizationId(token) {
|
|
6806
6797
|
const parts = token.split(".");
|
|
6807
6798
|
const signature = parts[2] || token;
|
|
6808
|
-
return (0,
|
|
6799
|
+
return (0, import_utils39.sha256Hex)(signature).substring(0, 16);
|
|
6809
6800
|
}
|
|
6810
6801
|
|
|
6811
6802
|
// libs/auth/src/authorization/orchestrated.authorization.ts
|
|
@@ -7174,7 +7165,7 @@ var OrchestratedAuthAccessorAdapter = class {
|
|
|
7174
7165
|
};
|
|
7175
7166
|
|
|
7176
7167
|
// libs/auth/src/authorization/dcr-client.registry.ts
|
|
7177
|
-
var
|
|
7168
|
+
var import_utils40 = require("@frontmcp/utils");
|
|
7178
7169
|
var DEFAULT_MAX_DYNAMIC_CLIENTS = 1e3;
|
|
7179
7170
|
function globMatch(pattern, input) {
|
|
7180
7171
|
let p = 0;
|
|
@@ -7300,7 +7291,7 @@ var DcrClientRegistry = class {
|
|
|
7300
7291
|
if (!isConfidential) return "ok";
|
|
7301
7292
|
if (!client.client_secret) return "invalid";
|
|
7302
7293
|
if (!presentedSecret) return "invalid";
|
|
7303
|
-
return (0,
|
|
7294
|
+
return (0, import_utils40.timingSafeEqual)((0, import_utils40.sha256)(presentedSecret), (0, import_utils40.sha256)(client.client_secret)) ? "ok" : "invalid";
|
|
7304
7295
|
}
|
|
7305
7296
|
/** Whether a client id is known to the registry. */
|
|
7306
7297
|
has(clientId) {
|
|
@@ -7388,7 +7379,7 @@ var DcrClientRegistry = class {
|
|
|
7388
7379
|
if (typeof presented !== "string" || presented.length === 0) {
|
|
7389
7380
|
return false;
|
|
7390
7381
|
}
|
|
7391
|
-
return (0,
|
|
7382
|
+
return (0, import_utils40.timingSafeEqual)((0, import_utils40.sha256)(presented), (0, import_utils40.sha256)(expected));
|
|
7392
7383
|
}
|
|
7393
7384
|
};
|
|
7394
7385
|
|
|
@@ -7717,6 +7708,7 @@ var cimdConfigSchema = import_lazy_zod9.z.object({
|
|
|
7717
7708
|
init_cimd_cache();
|
|
7718
7709
|
|
|
7719
7710
|
// libs/auth/src/cimd/cimd.service.ts
|
|
7711
|
+
var import_utils41 = require("@frontmcp/utils");
|
|
7720
7712
|
init_cimd_cache();
|
|
7721
7713
|
var CimdService = class {
|
|
7722
7714
|
config;
|
|
@@ -7891,7 +7883,7 @@ var CimdService = class {
|
|
|
7891
7883
|
httpStatus: 304
|
|
7892
7884
|
});
|
|
7893
7885
|
}
|
|
7894
|
-
if (
|
|
7886
|
+
if ((0, import_utils41.isRedirectResponse)(response)) {
|
|
7895
7887
|
const location = response.headers.get("location");
|
|
7896
7888
|
if (!location) {
|
|
7897
7889
|
throw new CimdFetchError(clientId, "Redirect response missing Location header", {
|
|
@@ -8508,10 +8500,48 @@ var publicAuthOptionsSchema = import_lazy_zod11.z.object({
|
|
|
8508
8500
|
signKey: jwkSchema.or(import_lazy_zod11.z.instanceof(Uint8Array)).optional()
|
|
8509
8501
|
});
|
|
8510
8502
|
|
|
8511
|
-
// libs/auth/src/options/
|
|
8503
|
+
// libs/auth/src/options/static.schema.ts
|
|
8512
8504
|
var import_lazy_zod12 = require("@frontmcp/lazy-zod");
|
|
8513
|
-
var
|
|
8514
|
-
mode: import_lazy_zod12.z.literal("
|
|
8505
|
+
var staticAuthOptionsSchema = import_lazy_zod12.z.object({
|
|
8506
|
+
mode: import_lazy_zod12.z.literal("static"),
|
|
8507
|
+
/**
|
|
8508
|
+
* Accepted credentials. Compared against the presented one in constant time,
|
|
8509
|
+
* over SHA-256 digests so neither the value nor its length leaks by timing.
|
|
8510
|
+
*
|
|
8511
|
+
* Read these from the environment — never commit them.
|
|
8512
|
+
*/
|
|
8513
|
+
tokens: import_lazy_zod12.z.array(import_lazy_zod12.z.string().min(1)).min(1),
|
|
8514
|
+
/**
|
|
8515
|
+
* Request header carrying the credential.
|
|
8516
|
+
* @default 'authorization'
|
|
8517
|
+
*/
|
|
8518
|
+
header: import_lazy_zod12.z.string().min(1).default("authorization"),
|
|
8519
|
+
/**
|
|
8520
|
+
* Scheme prefix to strip before comparing, matched case-insensitively. Set to
|
|
8521
|
+
* an empty string for headers that carry a bare token (e.g. `x-api-key`).
|
|
8522
|
+
* @default 'Bearer'
|
|
8523
|
+
*/
|
|
8524
|
+
scheme: import_lazy_zod12.z.string().default("Bearer"),
|
|
8525
|
+
/**
|
|
8526
|
+
* Scopes granted to a request that presents a valid token.
|
|
8527
|
+
* @default ['static']
|
|
8528
|
+
*/
|
|
8529
|
+
scopes: import_lazy_zod12.z.array(import_lazy_zod12.z.string()).default(["static"]),
|
|
8530
|
+
/**
|
|
8531
|
+
* Realm reported in the `WWW-Authenticate` challenge on failure.
|
|
8532
|
+
* @default 'mcp'
|
|
8533
|
+
*/
|
|
8534
|
+
realm: import_lazy_zod12.z.string().default("mcp"),
|
|
8535
|
+
/**
|
|
8536
|
+
* Tool/prompt access configuration, same shape the other modes accept.
|
|
8537
|
+
*/
|
|
8538
|
+
publicAccess: publicAccessConfigSchema.optional()
|
|
8539
|
+
});
|
|
8540
|
+
|
|
8541
|
+
// libs/auth/src/options/transparent.schema.ts
|
|
8542
|
+
var import_lazy_zod13 = require("@frontmcp/lazy-zod");
|
|
8543
|
+
var transparentAuthOptionsSchema = import_lazy_zod13.z.object({
|
|
8544
|
+
mode: import_lazy_zod13.z.literal("transparent"),
|
|
8515
8545
|
/**
|
|
8516
8546
|
* Flattened remote provider fields (provider, clientId, clientSecret, scopes, providerConfig)
|
|
8517
8547
|
*/
|
|
@@ -8520,28 +8550,28 @@ var transparentAuthOptionsSchema = import_lazy_zod12.z.object({
|
|
|
8520
8550
|
* Expected token audience
|
|
8521
8551
|
* If not set, defaults to the resource URL
|
|
8522
8552
|
*/
|
|
8523
|
-
expectedAudience:
|
|
8553
|
+
expectedAudience: import_lazy_zod13.z.union([import_lazy_zod13.z.string(), import_lazy_zod13.z.array(import_lazy_zod13.z.string())]).optional(),
|
|
8524
8554
|
/**
|
|
8525
8555
|
* Require an `aud` claim (reject audience-less tokens). Defaults to `false`
|
|
8526
8556
|
* for IdP compatibility; set `true` to reject tokens with no audience.
|
|
8527
8557
|
*/
|
|
8528
|
-
requireAudience:
|
|
8558
|
+
requireAudience: import_lazy_zod13.z.boolean().optional(),
|
|
8529
8559
|
/**
|
|
8530
8560
|
* Required scopes for access
|
|
8531
8561
|
* Empty array means any valid token is accepted
|
|
8532
8562
|
* @default []
|
|
8533
8563
|
*/
|
|
8534
|
-
requiredScopes:
|
|
8564
|
+
requiredScopes: import_lazy_zod13.z.array(import_lazy_zod13.z.string()).default([]),
|
|
8535
8565
|
/**
|
|
8536
8566
|
* Allow anonymous fallback when no token is provided
|
|
8537
8567
|
* @default false
|
|
8538
8568
|
*/
|
|
8539
|
-
allowAnonymous:
|
|
8569
|
+
allowAnonymous: import_lazy_zod13.z.boolean().default(false),
|
|
8540
8570
|
/**
|
|
8541
8571
|
* Scopes granted to anonymous sessions (when allowAnonymous=true)
|
|
8542
8572
|
* @default ['anonymous']
|
|
8543
8573
|
*/
|
|
8544
|
-
anonymousScopes:
|
|
8574
|
+
anonymousScopes: import_lazy_zod13.z.array(import_lazy_zod13.z.string()).default(["anonymous"]),
|
|
8545
8575
|
/**
|
|
8546
8576
|
* Public access config for anonymous users (when allowAnonymous=true)
|
|
8547
8577
|
*/
|
|
@@ -8549,13 +8579,13 @@ var transparentAuthOptionsSchema = import_lazy_zod12.z.object({
|
|
|
8549
8579
|
});
|
|
8550
8580
|
|
|
8551
8581
|
// libs/auth/src/options/orchestrated.schema.ts
|
|
8552
|
-
var
|
|
8553
|
-
var authSlotSchema =
|
|
8554
|
-
var authUiMapSchema =
|
|
8555
|
-
var authExtraHandlerSchema =
|
|
8582
|
+
var import_lazy_zod14 = require("@frontmcp/lazy-zod");
|
|
8583
|
+
var authSlotSchema = import_lazy_zod14.z.enum(["login", "consent", "incremental", "federated", "error"]);
|
|
8584
|
+
var authUiMapSchema = import_lazy_zod14.z.partialRecord(authSlotSchema, import_lazy_zod14.z.string().min(1));
|
|
8585
|
+
var authExtraHandlerSchema = import_lazy_zod14.z.custom((v) => typeof v === "function", {
|
|
8556
8586
|
message: "auth.extras entries must be handler functions (input, ctx) => AuthExtraResult."
|
|
8557
8587
|
});
|
|
8558
|
-
var authExtrasMapSchema =
|
|
8588
|
+
var authExtrasMapSchema = import_lazy_zod14.z.record(import_lazy_zod14.z.string().min(1), authExtraHandlerSchema);
|
|
8559
8589
|
var sharedAuthFields = {
|
|
8560
8590
|
local: localSigningConfigSchema.optional(),
|
|
8561
8591
|
tokenStorage: tokenStorageConfigSchema.default("memory"),
|
|
@@ -8563,13 +8593,13 @@ var sharedAuthFields = {
|
|
|
8563
8593
|
// Optional (no default) so an unset value resolves to the in-memory encrypted
|
|
8564
8594
|
// default at runtime; existing configs are unaffected.
|
|
8565
8595
|
secureStore: secureStoreConfigSchema.optional(),
|
|
8566
|
-
allowDefaultPublic:
|
|
8567
|
-
anonymousScopes:
|
|
8596
|
+
allowDefaultPublic: import_lazy_zod14.z.boolean().default(false),
|
|
8597
|
+
anonymousScopes: import_lazy_zod14.z.array(import_lazy_zod14.z.string()).default(["anonymous"]),
|
|
8568
8598
|
publicAccess: publicAccessConfigSchema.optional(),
|
|
8569
8599
|
consent: consentConfigSchema.optional(),
|
|
8570
8600
|
federatedAuth: federatedAuthConfigSchema.optional(),
|
|
8571
8601
|
refresh: tokenRefreshConfigSchema.optional(),
|
|
8572
|
-
expectedAudience:
|
|
8602
|
+
expectedAudience: import_lazy_zod14.z.union([import_lazy_zod14.z.string(), import_lazy_zod14.z.array(import_lazy_zod14.z.string())]).optional(),
|
|
8573
8603
|
incrementalAuth: incrementalAuthConfigSchema.optional(),
|
|
8574
8604
|
/**
|
|
8575
8605
|
* Require the OAuth client to be KNOWN (registered via DCR / pre-registered,
|
|
@@ -8585,46 +8615,46 @@ var sharedAuthFields = {
|
|
|
8585
8615
|
* matching for every client. Clients on a configured
|
|
8586
8616
|
* `dcr.allowedRedirectUris` allowlist still pass.
|
|
8587
8617
|
*/
|
|
8588
|
-
requireRegisteredClients:
|
|
8618
|
+
requireRegisteredClients: import_lazy_zod14.z.boolean().default(false),
|
|
8589
8619
|
cimd: cimdConfigSchema.optional(),
|
|
8590
8620
|
// #469 — custom auth UI as a slot→file map + extras name→handler map (per-app
|
|
8591
8621
|
// under splitByApp). Both optional; omitting them serves the built-in pages.
|
|
8592
8622
|
ui: authUiMapSchema.optional(),
|
|
8593
8623
|
extras: authExtrasMapSchema.optional()
|
|
8594
8624
|
};
|
|
8595
|
-
var loginFieldSchema =
|
|
8596
|
-
type:
|
|
8597
|
-
label:
|
|
8598
|
-
required:
|
|
8599
|
-
placeholder:
|
|
8600
|
-
options:
|
|
8625
|
+
var loginFieldSchema = import_lazy_zod14.z.object({
|
|
8626
|
+
type: import_lazy_zod14.z.enum(["text", "password", "email", "select", "hidden"]),
|
|
8627
|
+
label: import_lazy_zod14.z.string().optional(),
|
|
8628
|
+
required: import_lazy_zod14.z.boolean().optional(),
|
|
8629
|
+
placeholder: import_lazy_zod14.z.string().optional(),
|
|
8630
|
+
options: import_lazy_zod14.z.array(import_lazy_zod14.z.object({ value: import_lazy_zod14.z.string(), label: import_lazy_zod14.z.string() })).optional()
|
|
8601
8631
|
});
|
|
8602
|
-
var loginConfigSchema =
|
|
8603
|
-
title:
|
|
8604
|
-
subtitle:
|
|
8605
|
-
logoUri:
|
|
8606
|
-
fields:
|
|
8632
|
+
var loginConfigSchema = import_lazy_zod14.z.object({
|
|
8633
|
+
title: import_lazy_zod14.z.string().optional(),
|
|
8634
|
+
subtitle: import_lazy_zod14.z.string().optional(),
|
|
8635
|
+
logoUri: import_lazy_zod14.z.string().optional(),
|
|
8636
|
+
fields: import_lazy_zod14.z.record(import_lazy_zod14.z.string(), loginFieldSchema).optional(),
|
|
8607
8637
|
// Full HTML override — a function, validated structurally like other callbacks
|
|
8608
8638
|
// in the codebase (see http/cors handlers using z.custom<…>).
|
|
8609
|
-
render:
|
|
8639
|
+
render: import_lazy_zod14.z.custom((v) => typeof v === "function", {
|
|
8610
8640
|
message: "login.render must be a function"
|
|
8611
8641
|
}).optional(),
|
|
8612
|
-
subject:
|
|
8613
|
-
fromField:
|
|
8614
|
-
strategy:
|
|
8642
|
+
subject: import_lazy_zod14.z.object({
|
|
8643
|
+
fromField: import_lazy_zod14.z.string().optional(),
|
|
8644
|
+
strategy: import_lazy_zod14.z.enum(["per-session", "per-account"]).optional()
|
|
8615
8645
|
}).optional()
|
|
8616
8646
|
});
|
|
8617
|
-
var authenticateFnSchema =
|
|
8647
|
+
var authenticateFnSchema = import_lazy_zod14.z.custom((v) => typeof v === "function", {
|
|
8618
8648
|
message: "authenticate must be a function"
|
|
8619
8649
|
});
|
|
8620
|
-
var localAuthSchema =
|
|
8621
|
-
mode:
|
|
8650
|
+
var localAuthSchema = import_lazy_zod14.z.object({
|
|
8651
|
+
mode: import_lazy_zod14.z.literal("local"),
|
|
8622
8652
|
...sharedAuthFields,
|
|
8623
8653
|
// #468 — opt-out of the email requirement at /oauth/callback for
|
|
8624
8654
|
// single-operator local setups. Defaults preserve the historical behavior
|
|
8625
8655
|
// (email required) so existing configs are unaffected.
|
|
8626
|
-
requireEmail:
|
|
8627
|
-
anonymousSubject:
|
|
8656
|
+
requireEmail: import_lazy_zod14.z.boolean().default(true),
|
|
8657
|
+
anonymousSubject: import_lazy_zod14.z.string().min(1).default("local-operator"),
|
|
8628
8658
|
// Checkpoint 3a — declarative login customization + custom verification.
|
|
8629
8659
|
// Both optional; omitting them preserves the default login path exactly.
|
|
8630
8660
|
login: loginConfigSchema.optional(),
|
|
@@ -8632,7 +8662,7 @@ var localAuthSchema = import_lazy_zod13.z.object({
|
|
|
8632
8662
|
// Multi-OAuth-provider orchestration — declare upstream providers (GitHub,
|
|
8633
8663
|
// Slack, Jira, …) to federate at /oauth/authorize. Optional; omitting it
|
|
8634
8664
|
// preserves the default single-operator local login exactly.
|
|
8635
|
-
providers:
|
|
8665
|
+
providers: import_lazy_zod14.z.array(upstreamProviderSchema).optional(),
|
|
8636
8666
|
// Local-AS Dynamic Client Registration control surface (#462) — gate
|
|
8637
8667
|
// `POST /oauth/register`, allowlist redirect_uris/client_ids, require an
|
|
8638
8668
|
// initial access token, and seed pre-registered trusted clients. Optional;
|
|
@@ -8640,8 +8670,8 @@ var localAuthSchema = import_lazy_zod13.z.object({
|
|
|
8640
8670
|
// no allowlist; no initial access token).
|
|
8641
8671
|
dcr: localDcrConfigSchema.optional()
|
|
8642
8672
|
});
|
|
8643
|
-
var remoteAuthSchema =
|
|
8644
|
-
mode:
|
|
8673
|
+
var remoteAuthSchema = import_lazy_zod14.z.object({
|
|
8674
|
+
mode: import_lazy_zod14.z.literal("remote"),
|
|
8645
8675
|
...flatRemoteProviderFields,
|
|
8646
8676
|
...sharedAuthFields
|
|
8647
8677
|
});
|
|
@@ -8649,21 +8679,22 @@ var orchestratedLocalSchema = localAuthSchema;
|
|
|
8649
8679
|
var orchestratedRemoteSchema = remoteAuthSchema;
|
|
8650
8680
|
|
|
8651
8681
|
// libs/auth/src/options/schema.ts
|
|
8652
|
-
var
|
|
8653
|
-
var authOptionsSchema =
|
|
8682
|
+
var import_lazy_zod15 = require("@frontmcp/lazy-zod");
|
|
8683
|
+
var authOptionsSchema = import_lazy_zod15.z.union([
|
|
8654
8684
|
publicAuthOptionsSchema,
|
|
8685
|
+
staticAuthOptionsSchema,
|
|
8655
8686
|
transparentAuthOptionsSchema,
|
|
8656
8687
|
localAuthSchema,
|
|
8657
8688
|
remoteAuthSchema
|
|
8658
8689
|
]);
|
|
8659
8690
|
|
|
8660
8691
|
// libs/auth/src/options/app-auth.schema.ts
|
|
8661
|
-
var
|
|
8692
|
+
var import_lazy_zod16 = require("@frontmcp/lazy-zod");
|
|
8662
8693
|
var standaloneOptionSchema = {
|
|
8663
|
-
standalone:
|
|
8664
|
-
excludeFromParent:
|
|
8694
|
+
standalone: import_lazy_zod16.z.boolean().optional(),
|
|
8695
|
+
excludeFromParent: import_lazy_zod16.z.boolean().optional()
|
|
8665
8696
|
};
|
|
8666
|
-
var appAuthOptionsSchema =
|
|
8697
|
+
var appAuthOptionsSchema = import_lazy_zod16.z.union([
|
|
8667
8698
|
publicAuthOptionsSchema.extend(standaloneOptionSchema),
|
|
8668
8699
|
transparentAuthOptionsSchema.extend(standaloneOptionSchema),
|
|
8669
8700
|
localAuthSchema.extend(standaloneOptionSchema),
|
|
@@ -8677,6 +8708,9 @@ function parseAuthOptions(input) {
|
|
|
8677
8708
|
function isPublicMode(options) {
|
|
8678
8709
|
return options.mode === "public";
|
|
8679
8710
|
}
|
|
8711
|
+
function isStaticMode(options) {
|
|
8712
|
+
return options.mode === "static";
|
|
8713
|
+
}
|
|
8680
8714
|
function isTransparentMode(options) {
|
|
8681
8715
|
return options.mode === "transparent";
|
|
8682
8716
|
}
|
|
@@ -8703,108 +8737,108 @@ function allowsPublicAccess(options) {
|
|
|
8703
8737
|
}
|
|
8704
8738
|
|
|
8705
8739
|
// libs/auth/src/consent/consent.types.ts
|
|
8706
|
-
var
|
|
8707
|
-
var consentToolItemSchema =
|
|
8740
|
+
var import_lazy_zod17 = require("@frontmcp/lazy-zod");
|
|
8741
|
+
var consentToolItemSchema = import_lazy_zod17.z.object({
|
|
8708
8742
|
/** Tool ID (e.g., 'slack:send_message') */
|
|
8709
|
-
id:
|
|
8743
|
+
id: import_lazy_zod17.z.string().min(1),
|
|
8710
8744
|
/** Tool name for display */
|
|
8711
|
-
name:
|
|
8745
|
+
name: import_lazy_zod17.z.string().min(1),
|
|
8712
8746
|
/** Tool description */
|
|
8713
|
-
description:
|
|
8747
|
+
description: import_lazy_zod17.z.string().optional(),
|
|
8714
8748
|
/** App ID this tool belongs to */
|
|
8715
|
-
appId:
|
|
8749
|
+
appId: import_lazy_zod17.z.string().min(1),
|
|
8716
8750
|
/** App name for display */
|
|
8717
|
-
appName:
|
|
8751
|
+
appName: import_lazy_zod17.z.string().min(1),
|
|
8718
8752
|
/** Whether the tool is selected by default */
|
|
8719
|
-
defaultSelected:
|
|
8753
|
+
defaultSelected: import_lazy_zod17.z.boolean().default(true),
|
|
8720
8754
|
/** Whether this tool requires specific scopes */
|
|
8721
|
-
requiredScopes:
|
|
8755
|
+
requiredScopes: import_lazy_zod17.z.array(import_lazy_zod17.z.string()).optional(),
|
|
8722
8756
|
/** Category for grouping (e.g., 'read', 'write', 'admin') */
|
|
8723
|
-
category:
|
|
8757
|
+
category: import_lazy_zod17.z.string().optional()
|
|
8724
8758
|
});
|
|
8725
|
-
var consentSelectionSchema =
|
|
8759
|
+
var consentSelectionSchema = import_lazy_zod17.z.object({
|
|
8726
8760
|
/** Selected tool IDs */
|
|
8727
|
-
selectedTools:
|
|
8761
|
+
selectedTools: import_lazy_zod17.z.array(import_lazy_zod17.z.string()),
|
|
8728
8762
|
/** Whether all tools were selected */
|
|
8729
|
-
allSelected:
|
|
8763
|
+
allSelected: import_lazy_zod17.z.boolean(),
|
|
8730
8764
|
/** Timestamp when consent was given */
|
|
8731
|
-
consentedAt:
|
|
8765
|
+
consentedAt: import_lazy_zod17.z.string().datetime(),
|
|
8732
8766
|
/** Consent version for tracking changes */
|
|
8733
|
-
consentVersion:
|
|
8767
|
+
consentVersion: import_lazy_zod17.z.string().default("1.0")
|
|
8734
8768
|
});
|
|
8735
|
-
var consentStateSchema =
|
|
8769
|
+
var consentStateSchema = import_lazy_zod17.z.object({
|
|
8736
8770
|
/** Whether consent flow is enabled */
|
|
8737
|
-
enabled:
|
|
8771
|
+
enabled: import_lazy_zod17.z.boolean(),
|
|
8738
8772
|
/** Available tools for consent */
|
|
8739
|
-
availableTools:
|
|
8773
|
+
availableTools: import_lazy_zod17.z.array(consentToolItemSchema),
|
|
8740
8774
|
/** Pre-selected tools (from previous consent or defaults) */
|
|
8741
|
-
preselectedTools:
|
|
8775
|
+
preselectedTools: import_lazy_zod17.z.array(import_lazy_zod17.z.string()).optional(),
|
|
8742
8776
|
/** Whether to show all tools or group by app */
|
|
8743
|
-
groupByApp:
|
|
8777
|
+
groupByApp: import_lazy_zod17.z.boolean().default(true),
|
|
8744
8778
|
/** Custom consent message */
|
|
8745
|
-
customMessage:
|
|
8779
|
+
customMessage: import_lazy_zod17.z.string().optional()
|
|
8746
8780
|
});
|
|
8747
|
-
var federatedProviderItemSchema =
|
|
8781
|
+
var federatedProviderItemSchema = import_lazy_zod17.z.object({
|
|
8748
8782
|
/** Provider ID (derived or explicit) */
|
|
8749
|
-
id:
|
|
8783
|
+
id: import_lazy_zod17.z.string().min(1),
|
|
8750
8784
|
/** Provider display name */
|
|
8751
|
-
name:
|
|
8785
|
+
name: import_lazy_zod17.z.string().min(1),
|
|
8752
8786
|
/** Provider description */
|
|
8753
|
-
description:
|
|
8787
|
+
description: import_lazy_zod17.z.string().optional(),
|
|
8754
8788
|
/** Provider icon URL or emoji */
|
|
8755
|
-
icon:
|
|
8789
|
+
icon: import_lazy_zod17.z.string().optional(),
|
|
8756
8790
|
/** Provider type */
|
|
8757
|
-
type:
|
|
8791
|
+
type: import_lazy_zod17.z.enum(["local", "remote", "transparent"]),
|
|
8758
8792
|
/** OAuth provider URL (for remote providers) */
|
|
8759
|
-
providerUrl:
|
|
8793
|
+
providerUrl: import_lazy_zod17.z.string().url().optional(),
|
|
8760
8794
|
/** Apps using this provider */
|
|
8761
|
-
appIds:
|
|
8795
|
+
appIds: import_lazy_zod17.z.array(import_lazy_zod17.z.string()),
|
|
8762
8796
|
/** App names using this provider */
|
|
8763
|
-
appNames:
|
|
8797
|
+
appNames: import_lazy_zod17.z.array(import_lazy_zod17.z.string()),
|
|
8764
8798
|
/** Scopes required by this provider */
|
|
8765
|
-
scopes:
|
|
8799
|
+
scopes: import_lazy_zod17.z.array(import_lazy_zod17.z.string()),
|
|
8766
8800
|
/** Whether this is the primary/parent provider */
|
|
8767
|
-
isPrimary:
|
|
8801
|
+
isPrimary: import_lazy_zod17.z.boolean(),
|
|
8768
8802
|
/** Whether this provider is optional (can be skipped) */
|
|
8769
|
-
isOptional:
|
|
8803
|
+
isOptional: import_lazy_zod17.z.boolean().default(false)
|
|
8770
8804
|
});
|
|
8771
|
-
var federatedLoginStateSchema =
|
|
8805
|
+
var federatedLoginStateSchema = import_lazy_zod17.z.object({
|
|
8772
8806
|
/** All available providers */
|
|
8773
|
-
providers:
|
|
8807
|
+
providers: import_lazy_zod17.z.array(federatedProviderItemSchema),
|
|
8774
8808
|
/** Primary provider ID (if any) */
|
|
8775
|
-
primaryProviderId:
|
|
8809
|
+
primaryProviderId: import_lazy_zod17.z.string().optional(),
|
|
8776
8810
|
/** Whether user can skip optional providers */
|
|
8777
|
-
allowSkip:
|
|
8811
|
+
allowSkip: import_lazy_zod17.z.boolean().default(true),
|
|
8778
8812
|
/** Pre-selected provider IDs (from previous session) */
|
|
8779
|
-
preselectedProviders:
|
|
8813
|
+
preselectedProviders: import_lazy_zod17.z.array(import_lazy_zod17.z.string()).optional()
|
|
8780
8814
|
});
|
|
8781
|
-
var federatedSelectionSchema =
|
|
8815
|
+
var federatedSelectionSchema = import_lazy_zod17.z.object({
|
|
8782
8816
|
/** Selected provider IDs */
|
|
8783
|
-
selectedProviders:
|
|
8817
|
+
selectedProviders: import_lazy_zod17.z.array(import_lazy_zod17.z.string()),
|
|
8784
8818
|
/** Skipped provider IDs */
|
|
8785
|
-
skippedProviders:
|
|
8819
|
+
skippedProviders: import_lazy_zod17.z.array(import_lazy_zod17.z.string()),
|
|
8786
8820
|
/** Provider-specific metadata */
|
|
8787
|
-
providerMetadata:
|
|
8821
|
+
providerMetadata: import_lazy_zod17.z.record(import_lazy_zod17.z.string(), import_lazy_zod17.z.unknown()).optional()
|
|
8788
8822
|
});
|
|
8789
8823
|
|
|
8790
8824
|
// libs/auth/src/detection/auth-provider-detection.ts
|
|
8791
|
-
var
|
|
8792
|
-
var detectedAuthProviderSchema =
|
|
8793
|
-
id:
|
|
8794
|
-
providerUrl:
|
|
8795
|
-
mode:
|
|
8796
|
-
appIds:
|
|
8797
|
-
scopes:
|
|
8798
|
-
isParentProvider:
|
|
8825
|
+
var import_lazy_zod18 = require("@frontmcp/lazy-zod");
|
|
8826
|
+
var detectedAuthProviderSchema = import_lazy_zod18.z.object({
|
|
8827
|
+
id: import_lazy_zod18.z.string(),
|
|
8828
|
+
providerUrl: import_lazy_zod18.z.string().optional(),
|
|
8829
|
+
mode: import_lazy_zod18.z.enum(["public", "static", "transparent", "local", "remote"]),
|
|
8830
|
+
appIds: import_lazy_zod18.z.array(import_lazy_zod18.z.string()),
|
|
8831
|
+
scopes: import_lazy_zod18.z.array(import_lazy_zod18.z.string()),
|
|
8832
|
+
isParentProvider: import_lazy_zod18.z.boolean()
|
|
8799
8833
|
});
|
|
8800
|
-
var authProviderDetectionResultSchema =
|
|
8801
|
-
providers:
|
|
8802
|
-
requiresOrchestration:
|
|
8803
|
-
parentProviderId:
|
|
8804
|
-
childProviderIds:
|
|
8805
|
-
uniqueProviderCount:
|
|
8806
|
-
validationErrors:
|
|
8807
|
-
warnings:
|
|
8834
|
+
var authProviderDetectionResultSchema = import_lazy_zod18.z.object({
|
|
8835
|
+
providers: import_lazy_zod18.z.map(import_lazy_zod18.z.string(), detectedAuthProviderSchema),
|
|
8836
|
+
requiresOrchestration: import_lazy_zod18.z.boolean(),
|
|
8837
|
+
parentProviderId: import_lazy_zod18.z.string().optional(),
|
|
8838
|
+
childProviderIds: import_lazy_zod18.z.array(import_lazy_zod18.z.string()),
|
|
8839
|
+
uniqueProviderCount: import_lazy_zod18.z.number(),
|
|
8840
|
+
validationErrors: import_lazy_zod18.z.array(import_lazy_zod18.z.string()),
|
|
8841
|
+
warnings: import_lazy_zod18.z.array(import_lazy_zod18.z.string())
|
|
8808
8842
|
});
|
|
8809
8843
|
function deriveProviderId(options) {
|
|
8810
8844
|
if (isPublicMode(options)) {
|
|
@@ -9193,43 +9227,43 @@ var AudienceValidator = class _AudienceValidator {
|
|
|
9193
9227
|
};
|
|
9194
9228
|
|
|
9195
9229
|
// libs/auth/src/vault/auth-providers.types.ts
|
|
9196
|
-
var
|
|
9197
|
-
var credentialScopeSchema =
|
|
9198
|
-
var loadingStrategySchema =
|
|
9199
|
-
var getCredentialOptionsSchema =
|
|
9200
|
-
forceRefresh:
|
|
9201
|
-
scopes:
|
|
9202
|
-
timeout:
|
|
9230
|
+
var import_lazy_zod19 = require("@frontmcp/lazy-zod");
|
|
9231
|
+
var credentialScopeSchema = import_lazy_zod19.z.enum(["global", "user", "session"]);
|
|
9232
|
+
var loadingStrategySchema = import_lazy_zod19.z.enum(["eager", "lazy"]);
|
|
9233
|
+
var getCredentialOptionsSchema = import_lazy_zod19.z.object({
|
|
9234
|
+
forceRefresh: import_lazy_zod19.z.boolean().optional(),
|
|
9235
|
+
scopes: import_lazy_zod19.z.array(import_lazy_zod19.z.string()).optional(),
|
|
9236
|
+
timeout: import_lazy_zod19.z.number().positive().optional()
|
|
9203
9237
|
}).strict();
|
|
9204
|
-
var credentialProviderConfigSchema =
|
|
9205
|
-
name:
|
|
9206
|
-
description:
|
|
9238
|
+
var credentialProviderConfigSchema = import_lazy_zod19.z.object({
|
|
9239
|
+
name: import_lazy_zod19.z.string().min(1),
|
|
9240
|
+
description: import_lazy_zod19.z.string().optional(),
|
|
9207
9241
|
scope: credentialScopeSchema,
|
|
9208
9242
|
loading: loadingStrategySchema,
|
|
9209
|
-
cacheTtl:
|
|
9243
|
+
cacheTtl: import_lazy_zod19.z.number().nonnegative().optional(),
|
|
9210
9244
|
// Functions validated at runtime, not via Zod (Zod 4 compatibility)
|
|
9211
|
-
factory:
|
|
9212
|
-
refresh:
|
|
9213
|
-
toHeaders:
|
|
9214
|
-
metadata:
|
|
9215
|
-
required:
|
|
9245
|
+
factory: import_lazy_zod19.z.any(),
|
|
9246
|
+
refresh: import_lazy_zod19.z.any().optional(),
|
|
9247
|
+
toHeaders: import_lazy_zod19.z.any().optional(),
|
|
9248
|
+
metadata: import_lazy_zod19.z.record(import_lazy_zod19.z.string(), import_lazy_zod19.z.unknown()).optional(),
|
|
9249
|
+
required: import_lazy_zod19.z.boolean().optional()
|
|
9216
9250
|
}).strict();
|
|
9217
|
-
var authProviderMappingSchema =
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
name:
|
|
9221
|
-
required:
|
|
9222
|
-
scopes:
|
|
9223
|
-
alias:
|
|
9251
|
+
var authProviderMappingSchema = import_lazy_zod19.z.union([
|
|
9252
|
+
import_lazy_zod19.z.string(),
|
|
9253
|
+
import_lazy_zod19.z.object({
|
|
9254
|
+
name: import_lazy_zod19.z.string().min(1),
|
|
9255
|
+
required: import_lazy_zod19.z.boolean().optional().default(true),
|
|
9256
|
+
scopes: import_lazy_zod19.z.array(import_lazy_zod19.z.string()).optional(),
|
|
9257
|
+
alias: import_lazy_zod19.z.string().optional()
|
|
9224
9258
|
}).strict()
|
|
9225
9259
|
]);
|
|
9226
|
-
var authProvidersVaultOptionsSchema =
|
|
9227
|
-
enabled:
|
|
9228
|
-
useSharedStorage:
|
|
9229
|
-
namespace:
|
|
9230
|
-
defaultCacheTtl:
|
|
9231
|
-
maxCredentialsPerSession:
|
|
9232
|
-
providers:
|
|
9260
|
+
var authProvidersVaultOptionsSchema = import_lazy_zod19.z.object({
|
|
9261
|
+
enabled: import_lazy_zod19.z.boolean().optional(),
|
|
9262
|
+
useSharedStorage: import_lazy_zod19.z.boolean().optional().default(true),
|
|
9263
|
+
namespace: import_lazy_zod19.z.string().optional().default("authproviders:"),
|
|
9264
|
+
defaultCacheTtl: import_lazy_zod19.z.number().nonnegative().optional().default(36e5),
|
|
9265
|
+
maxCredentialsPerSession: import_lazy_zod19.z.number().positive().optional().default(100),
|
|
9266
|
+
providers: import_lazy_zod19.z.array(credentialProviderConfigSchema).optional()
|
|
9233
9267
|
}).strict();
|
|
9234
9268
|
|
|
9235
9269
|
// libs/auth/src/vault/credential-helpers.ts
|
|
@@ -9434,7 +9468,7 @@ var CredentialCache = class {
|
|
|
9434
9468
|
var AUTH_PROVIDERS_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:AUTH_PROVIDERS_ACCESSOR");
|
|
9435
9469
|
|
|
9436
9470
|
// libs/auth/src/vault/auth-providers.accessor.impl.ts
|
|
9437
|
-
var
|
|
9471
|
+
var import_utils44 = require("@frontmcp/utils");
|
|
9438
9472
|
var AuthProvidersAccessorImpl = class {
|
|
9439
9473
|
constructor(registry, vault, cache, loader, context, logger) {
|
|
9440
9474
|
this.registry = registry;
|
|
@@ -9649,7 +9683,7 @@ var AuthProvidersAccessorImpl = class {
|
|
|
9649
9683
|
return { [credential.headerName]: credential.key };
|
|
9650
9684
|
case "basic": {
|
|
9651
9685
|
const value = `${credential.username}:${credential.password}`;
|
|
9652
|
-
const encoded = credential.encodedValue ?? (0,
|
|
9686
|
+
const encoded = credential.encodedValue ?? (0, import_utils44.base64Encode)(new TextEncoder().encode(value));
|
|
9653
9687
|
return { Authorization: `Basic ${encoded}` };
|
|
9654
9688
|
}
|
|
9655
9689
|
case "custom":
|
|
@@ -10237,6 +10271,18 @@ var noopRelationshipResolver = {
|
|
|
10237
10271
|
return false;
|
|
10238
10272
|
}
|
|
10239
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
|
+
}
|
|
10240
10286
|
var AuthoritiesContextBuilder = class {
|
|
10241
10287
|
claimsMapping;
|
|
10242
10288
|
claimsResolver;
|
|
@@ -10254,7 +10300,7 @@ var AuthoritiesContextBuilder = class {
|
|
|
10254
10300
|
const resolved = this.claimsResolver(authInfo);
|
|
10255
10301
|
return {
|
|
10256
10302
|
user: {
|
|
10257
|
-
sub: authInfo
|
|
10303
|
+
sub: signedInSubject(resolveAuthUser(authInfo).sub),
|
|
10258
10304
|
roles: resolved.roles,
|
|
10259
10305
|
permissions: resolved.permissions,
|
|
10260
10306
|
claims: resolved.claims
|
|
@@ -10264,7 +10310,7 @@ var AuthoritiesContextBuilder = class {
|
|
|
10264
10310
|
relationships: this.relationshipResolver
|
|
10265
10311
|
};
|
|
10266
10312
|
}
|
|
10267
|
-
const user = authInfo
|
|
10313
|
+
const user = resolveAuthUser(authInfo);
|
|
10268
10314
|
const authorization = authInfo?.extra?.["authorization"];
|
|
10269
10315
|
const authorizationClaims = authorization?.["claims"] ?? {};
|
|
10270
10316
|
const rawClaims = {
|
|
@@ -10285,10 +10331,10 @@ var AuthoritiesContextBuilder = class {
|
|
|
10285
10331
|
} else {
|
|
10286
10332
|
permissions = toStringArray(user["permissions"] ?? []);
|
|
10287
10333
|
}
|
|
10288
|
-
const
|
|
10334
|
+
const mappedSub = this.claimsMapping?.userId ? resolveDotPath(rawClaims, this.claimsMapping.userId) : void 0;
|
|
10289
10335
|
return {
|
|
10290
10336
|
user: {
|
|
10291
|
-
sub,
|
|
10337
|
+
sub: signedInSubject(user.sub, mappedSub),
|
|
10292
10338
|
roles,
|
|
10293
10339
|
permissions,
|
|
10294
10340
|
claims: rawClaims
|
|
@@ -10320,15 +10366,17 @@ var FrontMcpAuthContextImpl = class {
|
|
|
10320
10366
|
roles;
|
|
10321
10367
|
permissions;
|
|
10322
10368
|
constructor(source, claimsMapping) {
|
|
10323
|
-
const rawUser = source
|
|
10324
|
-
const
|
|
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 : "");
|
|
10325
10373
|
this.user = Object.freeze({
|
|
10326
10374
|
sub,
|
|
10327
10375
|
name: rawUser.name,
|
|
10328
10376
|
email: rawUser.email,
|
|
10329
10377
|
picture: rawUser.picture
|
|
10330
10378
|
});
|
|
10331
|
-
this.isAnonymous =
|
|
10379
|
+
this.isAnonymous = signedInSub === void 0;
|
|
10332
10380
|
const extraAuth = source.extra?.["authorization"];
|
|
10333
10381
|
this.mode = String(
|
|
10334
10382
|
source.extra?.["authMode"] ?? extraAuth?.["mode"] ?? (source.extra?.["isPublic"] === true || rawUser["anonymous"] === true ? "public" : "authenticated")
|
|
@@ -10386,7 +10434,7 @@ var FrontMcpAuthContextImpl = class {
|
|
|
10386
10434
|
* Mirrors the logic in AuthoritiesContextBuilder.build().
|
|
10387
10435
|
*/
|
|
10388
10436
|
buildRawClaims(source) {
|
|
10389
|
-
const rawUser = source
|
|
10437
|
+
const rawUser = resolveAuthUser(source);
|
|
10390
10438
|
const extraAuth = source.extra?.["authorization"];
|
|
10391
10439
|
const authorizationClaims = extraAuth?.["claims"] ?? {};
|
|
10392
10440
|
return {
|
|
@@ -10451,20 +10499,20 @@ function resolveRequiredScopes(denial, mapping, authorities) {
|
|
|
10451
10499
|
}
|
|
10452
10500
|
|
|
10453
10501
|
// libs/auth/src/authorities/authorities.schema.ts
|
|
10454
|
-
var
|
|
10455
|
-
var rbacRolesPolicySchema =
|
|
10456
|
-
all:
|
|
10457
|
-
any:
|
|
10502
|
+
var import_lazy_zod20 = require("@frontmcp/lazy-zod");
|
|
10503
|
+
var rbacRolesPolicySchema = import_lazy_zod20.z.object({
|
|
10504
|
+
all: import_lazy_zod20.z.array(import_lazy_zod20.z.string().min(1)).optional(),
|
|
10505
|
+
any: import_lazy_zod20.z.array(import_lazy_zod20.z.string().min(1)).optional()
|
|
10458
10506
|
}).refine((data) => data.all !== void 0 || data.any !== void 0, {
|
|
10459
10507
|
message: 'Roles policy must have at least "all" or "any"'
|
|
10460
10508
|
});
|
|
10461
|
-
var rbacPermissionsPolicySchema =
|
|
10462
|
-
all:
|
|
10463
|
-
any:
|
|
10509
|
+
var rbacPermissionsPolicySchema = import_lazy_zod20.z.object({
|
|
10510
|
+
all: import_lazy_zod20.z.array(import_lazy_zod20.z.string().min(1)).optional(),
|
|
10511
|
+
any: import_lazy_zod20.z.array(import_lazy_zod20.z.string().min(1)).optional()
|
|
10464
10512
|
}).refine((data) => data.all !== void 0 || data.any !== void 0, {
|
|
10465
10513
|
message: 'Permissions policy must have at least "all" or "any"'
|
|
10466
10514
|
});
|
|
10467
|
-
var abacOperatorSchema =
|
|
10515
|
+
var abacOperatorSchema = import_lazy_zod20.z.enum([
|
|
10468
10516
|
"eq",
|
|
10469
10517
|
"neq",
|
|
10470
10518
|
"in",
|
|
@@ -10479,55 +10527,55 @@ var abacOperatorSchema = import_lazy_zod19.z.enum([
|
|
|
10479
10527
|
"exists",
|
|
10480
10528
|
"matches"
|
|
10481
10529
|
]);
|
|
10482
|
-
var abacConditionSchema =
|
|
10483
|
-
path:
|
|
10530
|
+
var abacConditionSchema = import_lazy_zod20.z.object({
|
|
10531
|
+
path: import_lazy_zod20.z.string().min(1),
|
|
10484
10532
|
op: abacOperatorSchema,
|
|
10485
|
-
value:
|
|
10533
|
+
value: import_lazy_zod20.z.unknown()
|
|
10486
10534
|
});
|
|
10487
|
-
var abacPolicySchema =
|
|
10488
|
-
match:
|
|
10489
|
-
conditions:
|
|
10535
|
+
var abacPolicySchema = import_lazy_zod20.z.object({
|
|
10536
|
+
match: import_lazy_zod20.z.record(import_lazy_zod20.z.string(), import_lazy_zod20.z.unknown()).optional(),
|
|
10537
|
+
conditions: import_lazy_zod20.z.array(abacConditionSchema).optional()
|
|
10490
10538
|
}).refine((data) => data.match !== void 0 || data.conditions !== void 0, {
|
|
10491
10539
|
message: 'Attributes policy must have at least "match" or "conditions"'
|
|
10492
10540
|
});
|
|
10493
|
-
var resourceIdRefSchema =
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10541
|
+
var resourceIdRefSchema = import_lazy_zod20.z.union([
|
|
10542
|
+
import_lazy_zod20.z.string().min(1),
|
|
10543
|
+
import_lazy_zod20.z.object({ fromInput: import_lazy_zod20.z.string().min(1) }).strict(),
|
|
10544
|
+
import_lazy_zod20.z.object({ fromClaims: import_lazy_zod20.z.string().min(1) }).strict()
|
|
10497
10545
|
]);
|
|
10498
|
-
var rebacPolicySchema =
|
|
10499
|
-
type:
|
|
10500
|
-
resource:
|
|
10546
|
+
var rebacPolicySchema = import_lazy_zod20.z.object({
|
|
10547
|
+
type: import_lazy_zod20.z.string().min(1),
|
|
10548
|
+
resource: import_lazy_zod20.z.string().min(1),
|
|
10501
10549
|
resourceId: resourceIdRefSchema
|
|
10502
10550
|
});
|
|
10503
10551
|
var basePolicyShape = {
|
|
10504
10552
|
roles: rbacRolesPolicySchema.optional(),
|
|
10505
10553
|
permissions: rbacPermissionsPolicySchema.optional(),
|
|
10506
10554
|
attributes: abacPolicySchema.optional(),
|
|
10507
|
-
relationships:
|
|
10508
|
-
custom:
|
|
10509
|
-
guards:
|
|
10510
|
-
operator:
|
|
10555
|
+
relationships: import_lazy_zod20.z.union([rebacPolicySchema, import_lazy_zod20.z.array(rebacPolicySchema)]).optional(),
|
|
10556
|
+
custom: import_lazy_zod20.z.record(import_lazy_zod20.z.string(), import_lazy_zod20.z.unknown()).optional(),
|
|
10557
|
+
guards: import_lazy_zod20.z.array(import_lazy_zod20.z.instanceof(Function)).optional(),
|
|
10558
|
+
operator: import_lazy_zod20.z.enum(["AND", "OR"]).optional()
|
|
10511
10559
|
};
|
|
10512
|
-
var authoritiesPolicySchema =
|
|
10513
|
-
() =>
|
|
10560
|
+
var authoritiesPolicySchema = import_lazy_zod20.z.lazy(
|
|
10561
|
+
() => import_lazy_zod20.z.object({
|
|
10514
10562
|
...basePolicyShape,
|
|
10515
10563
|
not: authoritiesPolicySchema.optional(),
|
|
10516
|
-
anyOf:
|
|
10517
|
-
allOf:
|
|
10564
|
+
anyOf: import_lazy_zod20.z.array(authoritiesPolicySchema).optional(),
|
|
10565
|
+
allOf: import_lazy_zod20.z.array(authoritiesPolicySchema).optional()
|
|
10518
10566
|
})
|
|
10519
10567
|
);
|
|
10520
|
-
var authoritiesMetadataSchema =
|
|
10521
|
-
|
|
10522
|
-
|
|
10568
|
+
var authoritiesMetadataSchema = import_lazy_zod20.z.union([
|
|
10569
|
+
import_lazy_zod20.z.string().min(1),
|
|
10570
|
+
import_lazy_zod20.z.array(import_lazy_zod20.z.string().min(1)).min(1),
|
|
10523
10571
|
authoritiesPolicySchema
|
|
10524
10572
|
]);
|
|
10525
|
-
var authoritiesClaimsMappingSchema =
|
|
10573
|
+
var authoritiesClaimsMappingSchema = import_lazy_zod20.z.record(import_lazy_zod20.z.string(), import_lazy_zod20.z.string().optional()).refine((data) => Object.values(data).some((v) => v !== void 0), {
|
|
10526
10574
|
message: "Claims mapping must have at least one mapping"
|
|
10527
10575
|
});
|
|
10528
|
-
var authoritiesConfigSchema =
|
|
10576
|
+
var authoritiesConfigSchema = import_lazy_zod20.z.object({
|
|
10529
10577
|
claimsMapping: authoritiesClaimsMappingSchema.optional(),
|
|
10530
|
-
profiles:
|
|
10578
|
+
profiles: import_lazy_zod20.z.record(import_lazy_zod20.z.string().min(1), authoritiesPolicySchema).optional()
|
|
10531
10579
|
});
|
|
10532
10580
|
|
|
10533
10581
|
// libs/auth/src/authorities/authorities.evaluator.ts
|
|
@@ -10605,8 +10653,9 @@ function resolveValue(value, ctx) {
|
|
|
10605
10653
|
}
|
|
10606
10654
|
function applyOperator(actual, op, expected) {
|
|
10607
10655
|
switch (op) {
|
|
10656
|
+
// A missing expected value (e.g. an absent fromInput) never matches, even an absent actual value
|
|
10608
10657
|
case "eq":
|
|
10609
|
-
return actual === expected;
|
|
10658
|
+
return expected !== void 0 && actual === expected;
|
|
10610
10659
|
case "neq":
|
|
10611
10660
|
return actual !== expected;
|
|
10612
10661
|
case "in":
|
|
@@ -10655,7 +10704,7 @@ function evaluateAbac(policy, ctx) {
|
|
|
10655
10704
|
for (const [path, expectedRaw] of Object.entries(policy.match)) {
|
|
10656
10705
|
const actual = resolveDotPath(envelope, path);
|
|
10657
10706
|
const expected = resolveValue(expectedRaw, ctx);
|
|
10658
|
-
if (actual !== expected) {
|
|
10707
|
+
if (expected === void 0 || actual !== expected) {
|
|
10659
10708
|
return {
|
|
10660
10709
|
granted: false,
|
|
10661
10710
|
deniedBy: `attributes.match: '${path}' expected '${String(expected)}' but got '${String(actual)}'`,
|
|
@@ -10695,6 +10744,15 @@ function resolveResourceId(ref, ctx) {
|
|
|
10695
10744
|
return void 0;
|
|
10696
10745
|
}
|
|
10697
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
|
+
}
|
|
10698
10756
|
const resourceId = resolveResourceId(policy.resourceId, ctx);
|
|
10699
10757
|
if (resourceId === void 0) {
|
|
10700
10758
|
return {
|
|
@@ -10709,11 +10767,11 @@ async function evaluateSingleRebac(policy, ctx) {
|
|
|
10709
10767
|
evaluatedPolicies: ["relationships"]
|
|
10710
10768
|
};
|
|
10711
10769
|
}
|
|
10712
|
-
const hasRelationship = await ctx.relationships.check(policy.type, policy.resource, resourceId,
|
|
10770
|
+
const hasRelationship = await ctx.relationships.check(policy.type, policy.resource, resourceId, userSub, ctx);
|
|
10713
10771
|
if (!hasRelationship) {
|
|
10714
10772
|
return {
|
|
10715
10773
|
granted: false,
|
|
10716
|
-
deniedBy: `relationships: user '${
|
|
10774
|
+
deniedBy: `relationships: user '${userSub}' is not '${policy.type}' of ${policy.resource}:${resourceId}`,
|
|
10717
10775
|
denial: {
|
|
10718
10776
|
kind: "relationships",
|
|
10719
10777
|
path: "relationships",
|
|
@@ -11231,6 +11289,8 @@ var FetchCredentialMiddleware = class {
|
|
|
11231
11289
|
InMemoryStoreRequiredError,
|
|
11232
11290
|
InvalidClientIdUrlError,
|
|
11233
11291
|
JwksService,
|
|
11292
|
+
JwtSecretRequiredError,
|
|
11293
|
+
JwtSecretWeakError,
|
|
11234
11294
|
LazyCredentialLoader,
|
|
11235
11295
|
NoProviderIdError,
|
|
11236
11296
|
NullOrchestratedAuthAccessor,
|
|
@@ -11385,6 +11445,7 @@ var FetchCredentialMiddleware = class {
|
|
|
11385
11445
|
headerApplier,
|
|
11386
11446
|
hkdfSha256,
|
|
11387
11447
|
incrementalAuthConfigSchema,
|
|
11448
|
+
isAnonymousSubject,
|
|
11388
11449
|
isCimdClientId,
|
|
11389
11450
|
isFrontMcpCredentials,
|
|
11390
11451
|
isJwt,
|
|
@@ -11401,6 +11462,7 @@ var FetchCredentialMiddleware = class {
|
|
|
11401
11462
|
isSoonExpiring,
|
|
11402
11463
|
isSoonExpiringProvider,
|
|
11403
11464
|
isSqliteTokenStorage,
|
|
11465
|
+
isStaticMode,
|
|
11404
11466
|
isTransparentMode,
|
|
11405
11467
|
jsonWebKeySetSchema,
|
|
11406
11468
|
jwkParametersSchema,
|
|
@@ -11460,6 +11522,7 @@ var FetchCredentialMiddleware = class {
|
|
|
11460
11522
|
startNextProvider,
|
|
11461
11523
|
statefulHttpTransportStateSchema,
|
|
11462
11524
|
statelessHttpTransportStateSchema,
|
|
11525
|
+
staticAuthOptionsSchema,
|
|
11463
11526
|
storedSessionSchema,
|
|
11464
11527
|
streamableHttpTransportStateSchema,
|
|
11465
11528
|
toEpochSeconds,
|