@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.
Files changed (36) hide show
  1. package/authorities/authorities.context.d.ts +16 -1
  2. package/authorities/authorities.context.d.ts.map +1 -1
  3. package/authorities/authorities.evaluator.d.ts +1 -1
  4. package/authorities/authorities.evaluator.d.ts.map +1 -1
  5. package/authorities/authorities.types.d.ts +2 -2
  6. package/authorities/authorities.types.d.ts.map +1 -1
  7. package/authorities/index.d.ts +1 -1
  8. package/authorities/index.d.ts.map +1 -1
  9. package/cimd/cimd.service.d.ts.map +1 -1
  10. package/cimd/cimd.validator.d.ts.map +1 -1
  11. package/context/frontmcp-auth-context.impl.d.ts.map +1 -1
  12. package/detection/auth-provider-detection.d.ts +2 -0
  13. package/detection/auth-provider-detection.d.ts.map +1 -1
  14. package/errors/auth-internal.errors.d.ts +12 -0
  15. package/errors/auth-internal.errors.d.ts.map +1 -1
  16. package/errors/index.d.ts +1 -1
  17. package/errors/index.d.ts.map +1 -1
  18. package/esm/index.mjs +306 -247
  19. package/esm/package.json +5 -5
  20. package/index.d.ts +1 -1
  21. package/index.d.ts.map +1 -1
  22. package/index.js +459 -396
  23. package/jwks/jwks.service.d.ts.map +1 -1
  24. package/options/index.d.ts +4 -2
  25. package/options/index.d.ts.map +1 -1
  26. package/options/interfaces.d.ts +20 -2
  27. package/options/interfaces.d.ts.map +1 -1
  28. package/options/schema.d.ts +13 -1
  29. package/options/schema.d.ts.map +1 -1
  30. package/options/static.schema.d.ts +27 -0
  31. package/options/static.schema.d.ts.map +1 -0
  32. package/options/typecheck.d.ts.map +1 -1
  33. package/options/utils.d.ts +7 -2
  34. package/options/utils.d.ts.map +1 -1
  35. package/package.json +5 -5
  36. package/session/authorization-vault.d.ts +1 -1
package/esm/index.mjs CHANGED
@@ -225,10 +225,14 @@ import {
225
225
  bytesToHex,
226
226
  createKeyPersistence,
227
227
  isProduction,
228
+ isRedirectResponse,
228
229
  randomBytes,
229
230
  rsaVerify
230
231
  } from "@frontmcp/utils";
231
232
 
233
+ // libs/auth/src/cimd/cimd.validator.ts
234
+ import { classifyIpAddress } from "@frontmcp/utils";
235
+
232
236
  // libs/auth/src/cimd/cimd.errors.ts
233
237
  var CimdError = class extends Error {
234
238
  /**
@@ -492,70 +496,38 @@ function isIpAddress(hostname) {
492
496
  }
493
497
  return false;
494
498
  }
499
+ var BLOCKED_RANGE_REASONS = /* @__PURE__ */ new Map([
500
+ ["0.0.0.0/8", "Current network addresses (0.x.x.x) are not allowed"],
501
+ ["10.0.0.0/8", "Private IP addresses (10.x.x.x) are not allowed"],
502
+ ["100.64.0.0/10", "Carrier-grade NAT addresses (100.64-127.x.x) are not allowed"],
503
+ ["127.0.0.0/8", "Loopback addresses (127.x.x.x) are not allowed"],
504
+ ["169.254.0.0/16", "Link-local addresses (169.254.x.x) are not allowed"],
505
+ ["172.16.0.0/12", "Private IP addresses (172.16-31.x.x) are not allowed"],
506
+ ["192.0.0.0/24", "IETF protocol-assignment addresses (192.0.0.0/24) are not allowed"],
507
+ ["192.168.0.0/16", "Private IP addresses (192.168.x.x) are not allowed"],
508
+ ["224.0.0.0/4", "Multicast addresses are not allowed"],
509
+ ["255.255.255.255/32", "Broadcast address is not allowed"],
510
+ ["::/128", "IPv6 unspecified address (::) is not allowed"],
511
+ ["::1/128", "IPv6 loopback address (::1) is not allowed"],
512
+ ["fc00::/7", "IPv6 unique local addresses (fc00::/7) are not allowed"],
513
+ ["fe80::/10", "IPv6 link-local addresses (fe80::/10) are not allowed"]
514
+ ]);
495
515
  function checkIpAddress(ip) {
496
- const cleanIp = ip.replace(/^\[|\]$/g, "");
497
- if (cleanIp.includes(".") && !cleanIp.includes(":")) {
498
- return checkIpv4(cleanIp);
499
- }
500
- return checkIpv6(cleanIp);
501
- }
502
- function checkIpv4(ip) {
503
- const parts = ip.split(".").map(Number);
504
- if (parts.length !== 4 || parts.some((p) => isNaN(p) || p < 0 || p > 255)) {
505
- return { allowed: false, reason: "Invalid IPv4 address" };
506
- }
507
- const [a, b, c, d] = parts;
508
- if (a === 127) {
509
- return { allowed: false, reason: "Loopback addresses (127.x.x.x) are not allowed" };
510
- }
511
- if (a === 10) {
512
- return { allowed: false, reason: "Private IP addresses (10.x.x.x) are not allowed" };
513
- }
514
- if (a === 172 && b >= 16 && b <= 31) {
515
- return { allowed: false, reason: "Private IP addresses (172.16-31.x.x) are not allowed" };
516
- }
517
- if (a === 192 && b === 168) {
518
- return { allowed: false, reason: "Private IP addresses (192.168.x.x) are not allowed" };
519
- }
520
- if (a === 169 && b === 254) {
521
- return { allowed: false, reason: "Link-local addresses (169.254.x.x) are not allowed" };
522
- }
523
- if (a === 100 && b >= 64 && b <= 127) {
524
- return { allowed: false, reason: "Carrier-grade NAT addresses (100.64-127.x.x) are not allowed" };
525
- }
526
- if (a === 192 && b === 0 && c === 0) {
527
- return { allowed: false, reason: "IETF protocol-assignment addresses (192.0.0.0/24) are not allowed" };
528
- }
529
- if (a === 0) {
530
- return { allowed: false, reason: "Current network addresses (0.x.x.x) are not allowed" };
531
- }
532
- if (a === 255 && b === 255 && c === 255 && d === 255) {
533
- return { allowed: false, reason: "Broadcast address is not allowed" };
534
- }
535
- if (a >= 224 && a <= 239) {
536
- return { allowed: false, reason: "Multicast addresses are not allowed" };
537
- }
538
- return { allowed: true, reason: "" };
539
- }
540
- function checkIpv6(ip) {
541
- const normalizedIp = ip.toLowerCase();
542
- if (normalizedIp === "::1") {
543
- return { allowed: false, reason: "IPv6 loopback address (::1) is not allowed" };
544
- }
545
- if (normalizedIp === "::" || normalizedIp === "0:0:0:0:0:0:0:0") {
546
- return { allowed: false, reason: "IPv6 unspecified address (::) is not allowed" };
547
- }
548
- if (normalizedIp.startsWith("fe8") || normalizedIp.startsWith("fe9") || normalizedIp.startsWith("fea") || normalizedIp.startsWith("feb")) {
549
- return { allowed: false, reason: "IPv6 link-local addresses (fe80::/10) are not allowed" };
550
- }
551
- if (normalizedIp.startsWith("fc") || normalizedIp.startsWith("fd")) {
552
- return { allowed: false, reason: "IPv6 unique local addresses (fc00::/7) are not allowed" };
516
+ const classification = classifyIpAddress(ip);
517
+ if (!classification) {
518
+ const bareIp = ip.replace(/^\[|\]$/g, "");
519
+ return {
520
+ allowed: false,
521
+ reason: bareIp.includes(":") ? `Malformed IPv6 address: ${bareIp}` : "Invalid IPv4 address"
522
+ };
553
523
  }
554
- const ipv4MappedMatch = normalizedIp.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
555
- if (ipv4MappedMatch) {
556
- return checkIpv4(ipv4MappedMatch[1]);
524
+ if (classification.range === "public") {
525
+ return { allowed: true, reason: "" };
557
526
  }
558
- return { allowed: true, reason: "" };
527
+ return {
528
+ allowed: false,
529
+ reason: BLOCKED_RANGE_REASONS.get(classification.cidr) ?? `Addresses in the ${classification.range} range (${classification.cidr}) are not allowed`
530
+ };
559
531
  }
560
532
  function isDomainInList(hostname, domainList) {
561
533
  const lowerHostname = hostname.toLowerCase();
@@ -964,11 +936,10 @@ var JwksService = class {
964
936
  // Follow redirects manually so each hop is re-validated (scheme + SSRF).
965
937
  redirect: "manual"
966
938
  });
967
- if (res.status >= 300 && res.status < 400) {
939
+ if (isRedirectResponse(res)) {
968
940
  const location = res.headers.get("location");
969
- if (!location || hop >= MAX_JWKS_FETCH_HOPS) {
970
- throw new Error("too many redirects");
971
- }
941
+ if (!location) throw new Error("redirect without a readable Location header");
942
+ if (hop >= MAX_JWKS_FETCH_HOPS) throw new Error("too many redirects");
972
943
  currentUrl = new URL(location, currentUrl).toString();
973
944
  continue;
974
945
  }
@@ -3544,6 +3515,22 @@ var SessionSecretRequiredError = class extends AuthInternalError {
3544
3515
  super(`Session secret is required for ${component}`, "SESSION_SECRET_REQUIRED");
3545
3516
  }
3546
3517
  };
3518
+ var JwtSecretRequiredError = class extends AuthInternalError {
3519
+ constructor(mode) {
3520
+ super(
3521
+ `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.`,
3522
+ "JWT_SECRET_REQUIRED"
3523
+ );
3524
+ }
3525
+ };
3526
+ var JwtSecretWeakError = class extends AuthInternalError {
3527
+ constructor(byteLength) {
3528
+ super(
3529
+ `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\`.`,
3530
+ "JWT_SECRET_INVALID"
3531
+ );
3532
+ }
3533
+ };
3547
3534
  var CredentialProviderAlreadyRegisteredError = class extends AuthInternalError {
3548
3535
  constructor(name) {
3549
3536
  super(`Credential provider "${name}" is already registered`, "CREDENTIAL_PROVIDER_ALREADY_REGISTERED");
@@ -7420,6 +7407,7 @@ init_cimd_cache();
7420
7407
 
7421
7408
  // libs/auth/src/cimd/cimd.service.ts
7422
7409
  init_cimd_cache();
7410
+ import { isRedirectResponse as isRedirectResponse2 } from "@frontmcp/utils";
7423
7411
  var CimdService = class {
7424
7412
  config;
7425
7413
  cacheConfig;
@@ -7593,7 +7581,7 @@ var CimdService = class {
7593
7581
  httpStatus: 304
7594
7582
  });
7595
7583
  }
7596
- if (response.status >= 300 && response.status < 400) {
7584
+ if (isRedirectResponse2(response)) {
7597
7585
  const location = response.headers.get("location");
7598
7586
  if (!location) {
7599
7587
  throw new CimdFetchError(clientId, "Redirect response missing Location header", {
@@ -8210,10 +8198,48 @@ var publicAuthOptionsSchema = z11.object({
8210
8198
  signKey: jwkSchema.or(z11.instanceof(Uint8Array)).optional()
8211
8199
  });
8212
8200
 
8213
- // libs/auth/src/options/transparent.schema.ts
8201
+ // libs/auth/src/options/static.schema.ts
8214
8202
  import { z as z12 } from "@frontmcp/lazy-zod";
8215
- var transparentAuthOptionsSchema = z12.object({
8216
- mode: z12.literal("transparent"),
8203
+ var staticAuthOptionsSchema = z12.object({
8204
+ mode: z12.literal("static"),
8205
+ /**
8206
+ * Accepted credentials. Compared against the presented one in constant time,
8207
+ * over SHA-256 digests so neither the value nor its length leaks by timing.
8208
+ *
8209
+ * Read these from the environment — never commit them.
8210
+ */
8211
+ tokens: z12.array(z12.string().min(1)).min(1),
8212
+ /**
8213
+ * Request header carrying the credential.
8214
+ * @default 'authorization'
8215
+ */
8216
+ header: z12.string().min(1).default("authorization"),
8217
+ /**
8218
+ * Scheme prefix to strip before comparing, matched case-insensitively. Set to
8219
+ * an empty string for headers that carry a bare token (e.g. `x-api-key`).
8220
+ * @default 'Bearer'
8221
+ */
8222
+ scheme: z12.string().default("Bearer"),
8223
+ /**
8224
+ * Scopes granted to a request that presents a valid token.
8225
+ * @default ['static']
8226
+ */
8227
+ scopes: z12.array(z12.string()).default(["static"]),
8228
+ /**
8229
+ * Realm reported in the `WWW-Authenticate` challenge on failure.
8230
+ * @default 'mcp'
8231
+ */
8232
+ realm: z12.string().default("mcp"),
8233
+ /**
8234
+ * Tool/prompt access configuration, same shape the other modes accept.
8235
+ */
8236
+ publicAccess: publicAccessConfigSchema.optional()
8237
+ });
8238
+
8239
+ // libs/auth/src/options/transparent.schema.ts
8240
+ import { z as z13 } from "@frontmcp/lazy-zod";
8241
+ var transparentAuthOptionsSchema = z13.object({
8242
+ mode: z13.literal("transparent"),
8217
8243
  /**
8218
8244
  * Flattened remote provider fields (provider, clientId, clientSecret, scopes, providerConfig)
8219
8245
  */
@@ -8222,28 +8248,28 @@ var transparentAuthOptionsSchema = z12.object({
8222
8248
  * Expected token audience
8223
8249
  * If not set, defaults to the resource URL
8224
8250
  */
8225
- expectedAudience: z12.union([z12.string(), z12.array(z12.string())]).optional(),
8251
+ expectedAudience: z13.union([z13.string(), z13.array(z13.string())]).optional(),
8226
8252
  /**
8227
8253
  * Require an `aud` claim (reject audience-less tokens). Defaults to `false`
8228
8254
  * for IdP compatibility; set `true` to reject tokens with no audience.
8229
8255
  */
8230
- requireAudience: z12.boolean().optional(),
8256
+ requireAudience: z13.boolean().optional(),
8231
8257
  /**
8232
8258
  * Required scopes for access
8233
8259
  * Empty array means any valid token is accepted
8234
8260
  * @default []
8235
8261
  */
8236
- requiredScopes: z12.array(z12.string()).default([]),
8262
+ requiredScopes: z13.array(z13.string()).default([]),
8237
8263
  /**
8238
8264
  * Allow anonymous fallback when no token is provided
8239
8265
  * @default false
8240
8266
  */
8241
- allowAnonymous: z12.boolean().default(false),
8267
+ allowAnonymous: z13.boolean().default(false),
8242
8268
  /**
8243
8269
  * Scopes granted to anonymous sessions (when allowAnonymous=true)
8244
8270
  * @default ['anonymous']
8245
8271
  */
8246
- anonymousScopes: z12.array(z12.string()).default(["anonymous"]),
8272
+ anonymousScopes: z13.array(z13.string()).default(["anonymous"]),
8247
8273
  /**
8248
8274
  * Public access config for anonymous users (when allowAnonymous=true)
8249
8275
  */
@@ -8251,13 +8277,13 @@ var transparentAuthOptionsSchema = z12.object({
8251
8277
  });
8252
8278
 
8253
8279
  // libs/auth/src/options/orchestrated.schema.ts
8254
- import { z as z13 } from "@frontmcp/lazy-zod";
8255
- var authSlotSchema = z13.enum(["login", "consent", "incremental", "federated", "error"]);
8256
- var authUiMapSchema = z13.partialRecord(authSlotSchema, z13.string().min(1));
8257
- var authExtraHandlerSchema = z13.custom((v) => typeof v === "function", {
8280
+ import { z as z14 } from "@frontmcp/lazy-zod";
8281
+ var authSlotSchema = z14.enum(["login", "consent", "incremental", "federated", "error"]);
8282
+ var authUiMapSchema = z14.partialRecord(authSlotSchema, z14.string().min(1));
8283
+ var authExtraHandlerSchema = z14.custom((v) => typeof v === "function", {
8258
8284
  message: "auth.extras entries must be handler functions (input, ctx) => AuthExtraResult."
8259
8285
  });
8260
- var authExtrasMapSchema = z13.record(z13.string().min(1), authExtraHandlerSchema);
8286
+ var authExtrasMapSchema = z14.record(z14.string().min(1), authExtraHandlerSchema);
8261
8287
  var sharedAuthFields = {
8262
8288
  local: localSigningConfigSchema.optional(),
8263
8289
  tokenStorage: tokenStorageConfigSchema.default("memory"),
@@ -8265,13 +8291,13 @@ var sharedAuthFields = {
8265
8291
  // Optional (no default) so an unset value resolves to the in-memory encrypted
8266
8292
  // default at runtime; existing configs are unaffected.
8267
8293
  secureStore: secureStoreConfigSchema.optional(),
8268
- allowDefaultPublic: z13.boolean().default(false),
8269
- anonymousScopes: z13.array(z13.string()).default(["anonymous"]),
8294
+ allowDefaultPublic: z14.boolean().default(false),
8295
+ anonymousScopes: z14.array(z14.string()).default(["anonymous"]),
8270
8296
  publicAccess: publicAccessConfigSchema.optional(),
8271
8297
  consent: consentConfigSchema.optional(),
8272
8298
  federatedAuth: federatedAuthConfigSchema.optional(),
8273
8299
  refresh: tokenRefreshConfigSchema.optional(),
8274
- expectedAudience: z13.union([z13.string(), z13.array(z13.string())]).optional(),
8300
+ expectedAudience: z14.union([z14.string(), z14.array(z14.string())]).optional(),
8275
8301
  incrementalAuth: incrementalAuthConfigSchema.optional(),
8276
8302
  /**
8277
8303
  * Require the OAuth client to be KNOWN (registered via DCR / pre-registered,
@@ -8287,46 +8313,46 @@ var sharedAuthFields = {
8287
8313
  * matching for every client. Clients on a configured
8288
8314
  * `dcr.allowedRedirectUris` allowlist still pass.
8289
8315
  */
8290
- requireRegisteredClients: z13.boolean().default(false),
8316
+ requireRegisteredClients: z14.boolean().default(false),
8291
8317
  cimd: cimdConfigSchema.optional(),
8292
8318
  // #469 — custom auth UI as a slot→file map + extras name→handler map (per-app
8293
8319
  // under splitByApp). Both optional; omitting them serves the built-in pages.
8294
8320
  ui: authUiMapSchema.optional(),
8295
8321
  extras: authExtrasMapSchema.optional()
8296
8322
  };
8297
- var loginFieldSchema = z13.object({
8298
- type: z13.enum(["text", "password", "email", "select", "hidden"]),
8299
- label: z13.string().optional(),
8300
- required: z13.boolean().optional(),
8301
- placeholder: z13.string().optional(),
8302
- options: z13.array(z13.object({ value: z13.string(), label: z13.string() })).optional()
8323
+ var loginFieldSchema = z14.object({
8324
+ type: z14.enum(["text", "password", "email", "select", "hidden"]),
8325
+ label: z14.string().optional(),
8326
+ required: z14.boolean().optional(),
8327
+ placeholder: z14.string().optional(),
8328
+ options: z14.array(z14.object({ value: z14.string(), label: z14.string() })).optional()
8303
8329
  });
8304
- var loginConfigSchema = z13.object({
8305
- title: z13.string().optional(),
8306
- subtitle: z13.string().optional(),
8307
- logoUri: z13.string().optional(),
8308
- fields: z13.record(z13.string(), loginFieldSchema).optional(),
8330
+ var loginConfigSchema = z14.object({
8331
+ title: z14.string().optional(),
8332
+ subtitle: z14.string().optional(),
8333
+ logoUri: z14.string().optional(),
8334
+ fields: z14.record(z14.string(), loginFieldSchema).optional(),
8309
8335
  // Full HTML override — a function, validated structurally like other callbacks
8310
8336
  // in the codebase (see http/cors handlers using z.custom<…>).
8311
- render: z13.custom((v) => typeof v === "function", {
8337
+ render: z14.custom((v) => typeof v === "function", {
8312
8338
  message: "login.render must be a function"
8313
8339
  }).optional(),
8314
- subject: z13.object({
8315
- fromField: z13.string().optional(),
8316
- strategy: z13.enum(["per-session", "per-account"]).optional()
8340
+ subject: z14.object({
8341
+ fromField: z14.string().optional(),
8342
+ strategy: z14.enum(["per-session", "per-account"]).optional()
8317
8343
  }).optional()
8318
8344
  });
8319
- var authenticateFnSchema = z13.custom((v) => typeof v === "function", {
8345
+ var authenticateFnSchema = z14.custom((v) => typeof v === "function", {
8320
8346
  message: "authenticate must be a function"
8321
8347
  });
8322
- var localAuthSchema = z13.object({
8323
- mode: z13.literal("local"),
8348
+ var localAuthSchema = z14.object({
8349
+ mode: z14.literal("local"),
8324
8350
  ...sharedAuthFields,
8325
8351
  // #468 — opt-out of the email requirement at /oauth/callback for
8326
8352
  // single-operator local setups. Defaults preserve the historical behavior
8327
8353
  // (email required) so existing configs are unaffected.
8328
- requireEmail: z13.boolean().default(true),
8329
- anonymousSubject: z13.string().min(1).default("local-operator"),
8354
+ requireEmail: z14.boolean().default(true),
8355
+ anonymousSubject: z14.string().min(1).default("local-operator"),
8330
8356
  // Checkpoint 3a — declarative login customization + custom verification.
8331
8357
  // Both optional; omitting them preserves the default login path exactly.
8332
8358
  login: loginConfigSchema.optional(),
@@ -8334,7 +8360,7 @@ var localAuthSchema = z13.object({
8334
8360
  // Multi-OAuth-provider orchestration — declare upstream providers (GitHub,
8335
8361
  // Slack, Jira, …) to federate at /oauth/authorize. Optional; omitting it
8336
8362
  // preserves the default single-operator local login exactly.
8337
- providers: z13.array(upstreamProviderSchema).optional(),
8363
+ providers: z14.array(upstreamProviderSchema).optional(),
8338
8364
  // Local-AS Dynamic Client Registration control surface (#462) — gate
8339
8365
  // `POST /oauth/register`, allowlist redirect_uris/client_ids, require an
8340
8366
  // initial access token, and seed pre-registered trusted clients. Optional;
@@ -8342,8 +8368,8 @@ var localAuthSchema = z13.object({
8342
8368
  // no allowlist; no initial access token).
8343
8369
  dcr: localDcrConfigSchema.optional()
8344
8370
  });
8345
- var remoteAuthSchema = z13.object({
8346
- mode: z13.literal("remote"),
8371
+ var remoteAuthSchema = z14.object({
8372
+ mode: z14.literal("remote"),
8347
8373
  ...flatRemoteProviderFields,
8348
8374
  ...sharedAuthFields
8349
8375
  });
@@ -8351,21 +8377,22 @@ var orchestratedLocalSchema = localAuthSchema;
8351
8377
  var orchestratedRemoteSchema = remoteAuthSchema;
8352
8378
 
8353
8379
  // libs/auth/src/options/schema.ts
8354
- import { z as z14 } from "@frontmcp/lazy-zod";
8355
- var authOptionsSchema = z14.union([
8380
+ import { z as z15 } from "@frontmcp/lazy-zod";
8381
+ var authOptionsSchema = z15.union([
8356
8382
  publicAuthOptionsSchema,
8383
+ staticAuthOptionsSchema,
8357
8384
  transparentAuthOptionsSchema,
8358
8385
  localAuthSchema,
8359
8386
  remoteAuthSchema
8360
8387
  ]);
8361
8388
 
8362
8389
  // libs/auth/src/options/app-auth.schema.ts
8363
- import { z as z15 } from "@frontmcp/lazy-zod";
8390
+ import { z as z16 } from "@frontmcp/lazy-zod";
8364
8391
  var standaloneOptionSchema = {
8365
- standalone: z15.boolean().optional(),
8366
- excludeFromParent: z15.boolean().optional()
8392
+ standalone: z16.boolean().optional(),
8393
+ excludeFromParent: z16.boolean().optional()
8367
8394
  };
8368
- var appAuthOptionsSchema = z15.union([
8395
+ var appAuthOptionsSchema = z16.union([
8369
8396
  publicAuthOptionsSchema.extend(standaloneOptionSchema),
8370
8397
  transparentAuthOptionsSchema.extend(standaloneOptionSchema),
8371
8398
  localAuthSchema.extend(standaloneOptionSchema),
@@ -8379,6 +8406,9 @@ function parseAuthOptions(input) {
8379
8406
  function isPublicMode(options) {
8380
8407
  return options.mode === "public";
8381
8408
  }
8409
+ function isStaticMode(options) {
8410
+ return options.mode === "static";
8411
+ }
8382
8412
  function isTransparentMode(options) {
8383
8413
  return options.mode === "transparent";
8384
8414
  }
@@ -8405,108 +8435,108 @@ function allowsPublicAccess(options) {
8405
8435
  }
8406
8436
 
8407
8437
  // libs/auth/src/consent/consent.types.ts
8408
- import { z as z16 } from "@frontmcp/lazy-zod";
8409
- var consentToolItemSchema = z16.object({
8438
+ import { z as z17 } from "@frontmcp/lazy-zod";
8439
+ var consentToolItemSchema = z17.object({
8410
8440
  /** Tool ID (e.g., 'slack:send_message') */
8411
- id: z16.string().min(1),
8441
+ id: z17.string().min(1),
8412
8442
  /** Tool name for display */
8413
- name: z16.string().min(1),
8443
+ name: z17.string().min(1),
8414
8444
  /** Tool description */
8415
- description: z16.string().optional(),
8445
+ description: z17.string().optional(),
8416
8446
  /** App ID this tool belongs to */
8417
- appId: z16.string().min(1),
8447
+ appId: z17.string().min(1),
8418
8448
  /** App name for display */
8419
- appName: z16.string().min(1),
8449
+ appName: z17.string().min(1),
8420
8450
  /** Whether the tool is selected by default */
8421
- defaultSelected: z16.boolean().default(true),
8451
+ defaultSelected: z17.boolean().default(true),
8422
8452
  /** Whether this tool requires specific scopes */
8423
- requiredScopes: z16.array(z16.string()).optional(),
8453
+ requiredScopes: z17.array(z17.string()).optional(),
8424
8454
  /** Category for grouping (e.g., 'read', 'write', 'admin') */
8425
- category: z16.string().optional()
8455
+ category: z17.string().optional()
8426
8456
  });
8427
- var consentSelectionSchema = z16.object({
8457
+ var consentSelectionSchema = z17.object({
8428
8458
  /** Selected tool IDs */
8429
- selectedTools: z16.array(z16.string()),
8459
+ selectedTools: z17.array(z17.string()),
8430
8460
  /** Whether all tools were selected */
8431
- allSelected: z16.boolean(),
8461
+ allSelected: z17.boolean(),
8432
8462
  /** Timestamp when consent was given */
8433
- consentedAt: z16.string().datetime(),
8463
+ consentedAt: z17.string().datetime(),
8434
8464
  /** Consent version for tracking changes */
8435
- consentVersion: z16.string().default("1.0")
8465
+ consentVersion: z17.string().default("1.0")
8436
8466
  });
8437
- var consentStateSchema = z16.object({
8467
+ var consentStateSchema = z17.object({
8438
8468
  /** Whether consent flow is enabled */
8439
- enabled: z16.boolean(),
8469
+ enabled: z17.boolean(),
8440
8470
  /** Available tools for consent */
8441
- availableTools: z16.array(consentToolItemSchema),
8471
+ availableTools: z17.array(consentToolItemSchema),
8442
8472
  /** Pre-selected tools (from previous consent or defaults) */
8443
- preselectedTools: z16.array(z16.string()).optional(),
8473
+ preselectedTools: z17.array(z17.string()).optional(),
8444
8474
  /** Whether to show all tools or group by app */
8445
- groupByApp: z16.boolean().default(true),
8475
+ groupByApp: z17.boolean().default(true),
8446
8476
  /** Custom consent message */
8447
- customMessage: z16.string().optional()
8477
+ customMessage: z17.string().optional()
8448
8478
  });
8449
- var federatedProviderItemSchema = z16.object({
8479
+ var federatedProviderItemSchema = z17.object({
8450
8480
  /** Provider ID (derived or explicit) */
8451
- id: z16.string().min(1),
8481
+ id: z17.string().min(1),
8452
8482
  /** Provider display name */
8453
- name: z16.string().min(1),
8483
+ name: z17.string().min(1),
8454
8484
  /** Provider description */
8455
- description: z16.string().optional(),
8485
+ description: z17.string().optional(),
8456
8486
  /** Provider icon URL or emoji */
8457
- icon: z16.string().optional(),
8487
+ icon: z17.string().optional(),
8458
8488
  /** Provider type */
8459
- type: z16.enum(["local", "remote", "transparent"]),
8489
+ type: z17.enum(["local", "remote", "transparent"]),
8460
8490
  /** OAuth provider URL (for remote providers) */
8461
- providerUrl: z16.string().url().optional(),
8491
+ providerUrl: z17.string().url().optional(),
8462
8492
  /** Apps using this provider */
8463
- appIds: z16.array(z16.string()),
8493
+ appIds: z17.array(z17.string()),
8464
8494
  /** App names using this provider */
8465
- appNames: z16.array(z16.string()),
8495
+ appNames: z17.array(z17.string()),
8466
8496
  /** Scopes required by this provider */
8467
- scopes: z16.array(z16.string()),
8497
+ scopes: z17.array(z17.string()),
8468
8498
  /** Whether this is the primary/parent provider */
8469
- isPrimary: z16.boolean(),
8499
+ isPrimary: z17.boolean(),
8470
8500
  /** Whether this provider is optional (can be skipped) */
8471
- isOptional: z16.boolean().default(false)
8501
+ isOptional: z17.boolean().default(false)
8472
8502
  });
8473
- var federatedLoginStateSchema = z16.object({
8503
+ var federatedLoginStateSchema = z17.object({
8474
8504
  /** All available providers */
8475
- providers: z16.array(federatedProviderItemSchema),
8505
+ providers: z17.array(federatedProviderItemSchema),
8476
8506
  /** Primary provider ID (if any) */
8477
- primaryProviderId: z16.string().optional(),
8507
+ primaryProviderId: z17.string().optional(),
8478
8508
  /** Whether user can skip optional providers */
8479
- allowSkip: z16.boolean().default(true),
8509
+ allowSkip: z17.boolean().default(true),
8480
8510
  /** Pre-selected provider IDs (from previous session) */
8481
- preselectedProviders: z16.array(z16.string()).optional()
8511
+ preselectedProviders: z17.array(z17.string()).optional()
8482
8512
  });
8483
- var federatedSelectionSchema = z16.object({
8513
+ var federatedSelectionSchema = z17.object({
8484
8514
  /** Selected provider IDs */
8485
- selectedProviders: z16.array(z16.string()),
8515
+ selectedProviders: z17.array(z17.string()),
8486
8516
  /** Skipped provider IDs */
8487
- skippedProviders: z16.array(z16.string()),
8517
+ skippedProviders: z17.array(z17.string()),
8488
8518
  /** Provider-specific metadata */
8489
- providerMetadata: z16.record(z16.string(), z16.unknown()).optional()
8519
+ providerMetadata: z17.record(z17.string(), z17.unknown()).optional()
8490
8520
  });
8491
8521
 
8492
8522
  // libs/auth/src/detection/auth-provider-detection.ts
8493
- import { z as z17 } from "@frontmcp/lazy-zod";
8494
- var detectedAuthProviderSchema = z17.object({
8495
- id: z17.string(),
8496
- providerUrl: z17.string().optional(),
8497
- mode: z17.enum(["public", "transparent", "local", "remote"]),
8498
- appIds: z17.array(z17.string()),
8499
- scopes: z17.array(z17.string()),
8500
- isParentProvider: z17.boolean()
8523
+ import { z as z18 } from "@frontmcp/lazy-zod";
8524
+ var detectedAuthProviderSchema = z18.object({
8525
+ id: z18.string(),
8526
+ providerUrl: z18.string().optional(),
8527
+ mode: z18.enum(["public", "static", "transparent", "local", "remote"]),
8528
+ appIds: z18.array(z18.string()),
8529
+ scopes: z18.array(z18.string()),
8530
+ isParentProvider: z18.boolean()
8501
8531
  });
8502
- var authProviderDetectionResultSchema = z17.object({
8503
- providers: z17.map(z17.string(), detectedAuthProviderSchema),
8504
- requiresOrchestration: z17.boolean(),
8505
- parentProviderId: z17.string().optional(),
8506
- childProviderIds: z17.array(z17.string()),
8507
- uniqueProviderCount: z17.number(),
8508
- validationErrors: z17.array(z17.string()),
8509
- warnings: z17.array(z17.string())
8532
+ var authProviderDetectionResultSchema = z18.object({
8533
+ providers: z18.map(z18.string(), detectedAuthProviderSchema),
8534
+ requiresOrchestration: z18.boolean(),
8535
+ parentProviderId: z18.string().optional(),
8536
+ childProviderIds: z18.array(z18.string()),
8537
+ uniqueProviderCount: z18.number(),
8538
+ validationErrors: z18.array(z18.string()),
8539
+ warnings: z18.array(z18.string())
8510
8540
  });
8511
8541
  function deriveProviderId(options) {
8512
8542
  if (isPublicMode(options)) {
@@ -8895,43 +8925,43 @@ var AudienceValidator = class _AudienceValidator {
8895
8925
  };
8896
8926
 
8897
8927
  // libs/auth/src/vault/auth-providers.types.ts
8898
- import { z as z18 } from "@frontmcp/lazy-zod";
8899
- var credentialScopeSchema = z18.enum(["global", "user", "session"]);
8900
- var loadingStrategySchema = z18.enum(["eager", "lazy"]);
8901
- var getCredentialOptionsSchema = z18.object({
8902
- forceRefresh: z18.boolean().optional(),
8903
- scopes: z18.array(z18.string()).optional(),
8904
- timeout: z18.number().positive().optional()
8928
+ import { z as z19 } from "@frontmcp/lazy-zod";
8929
+ var credentialScopeSchema = z19.enum(["global", "user", "session"]);
8930
+ var loadingStrategySchema = z19.enum(["eager", "lazy"]);
8931
+ var getCredentialOptionsSchema = z19.object({
8932
+ forceRefresh: z19.boolean().optional(),
8933
+ scopes: z19.array(z19.string()).optional(),
8934
+ timeout: z19.number().positive().optional()
8905
8935
  }).strict();
8906
- var credentialProviderConfigSchema = z18.object({
8907
- name: z18.string().min(1),
8908
- description: z18.string().optional(),
8936
+ var credentialProviderConfigSchema = z19.object({
8937
+ name: z19.string().min(1),
8938
+ description: z19.string().optional(),
8909
8939
  scope: credentialScopeSchema,
8910
8940
  loading: loadingStrategySchema,
8911
- cacheTtl: z18.number().nonnegative().optional(),
8941
+ cacheTtl: z19.number().nonnegative().optional(),
8912
8942
  // Functions validated at runtime, not via Zod (Zod 4 compatibility)
8913
- factory: z18.any(),
8914
- refresh: z18.any().optional(),
8915
- toHeaders: z18.any().optional(),
8916
- metadata: z18.record(z18.string(), z18.unknown()).optional(),
8917
- required: z18.boolean().optional()
8943
+ factory: z19.any(),
8944
+ refresh: z19.any().optional(),
8945
+ toHeaders: z19.any().optional(),
8946
+ metadata: z19.record(z19.string(), z19.unknown()).optional(),
8947
+ required: z19.boolean().optional()
8918
8948
  }).strict();
8919
- var authProviderMappingSchema = z18.union([
8920
- z18.string(),
8921
- z18.object({
8922
- name: z18.string().min(1),
8923
- required: z18.boolean().optional().default(true),
8924
- scopes: z18.array(z18.string()).optional(),
8925
- alias: z18.string().optional()
8949
+ var authProviderMappingSchema = z19.union([
8950
+ z19.string(),
8951
+ z19.object({
8952
+ name: z19.string().min(1),
8953
+ required: z19.boolean().optional().default(true),
8954
+ scopes: z19.array(z19.string()).optional(),
8955
+ alias: z19.string().optional()
8926
8956
  }).strict()
8927
8957
  ]);
8928
- var authProvidersVaultOptionsSchema = z18.object({
8929
- enabled: z18.boolean().optional(),
8930
- useSharedStorage: z18.boolean().optional().default(true),
8931
- namespace: z18.string().optional().default("authproviders:"),
8932
- defaultCacheTtl: z18.number().nonnegative().optional().default(36e5),
8933
- maxCredentialsPerSession: z18.number().positive().optional().default(100),
8934
- providers: z18.array(credentialProviderConfigSchema).optional()
8958
+ var authProvidersVaultOptionsSchema = z19.object({
8959
+ enabled: z19.boolean().optional(),
8960
+ useSharedStorage: z19.boolean().optional().default(true),
8961
+ namespace: z19.string().optional().default("authproviders:"),
8962
+ defaultCacheTtl: z19.number().nonnegative().optional().default(36e5),
8963
+ maxCredentialsPerSession: z19.number().positive().optional().default(100),
8964
+ providers: z19.array(credentialProviderConfigSchema).optional()
8935
8965
  }).strict();
8936
8966
 
8937
8967
  // libs/auth/src/vault/credential-helpers.ts
@@ -9939,6 +9969,18 @@ var noopRelationshipResolver = {
9939
9969
  return false;
9940
9970
  }
9941
9971
  };
9972
+ function resolveAuthUser(authInfo) {
9973
+ const extraUser = authInfo?.extra?.["user"];
9974
+ if (authInfo?.user) return authInfo.user;
9975
+ return typeof extraUser === "object" && extraUser !== null ? extraUser : {};
9976
+ }
9977
+ function isAnonymousSubject(sub) {
9978
+ return typeof sub !== "string" || sub === "" || sub.startsWith("anon:");
9979
+ }
9980
+ function signedInSubject(rawSub, mappedSub) {
9981
+ if (rawSub !== void 0 && isAnonymousSubject(rawSub)) return void 0;
9982
+ return [mappedSub, rawSub].find((candidate) => !isAnonymousSubject(candidate));
9983
+ }
9942
9984
  var AuthoritiesContextBuilder = class {
9943
9985
  claimsMapping;
9944
9986
  claimsResolver;
@@ -9956,7 +9998,7 @@ var AuthoritiesContextBuilder = class {
9956
9998
  const resolved = this.claimsResolver(authInfo);
9957
9999
  return {
9958
10000
  user: {
9959
- sub: authInfo?.user?.sub ?? "",
10001
+ sub: signedInSubject(resolveAuthUser(authInfo).sub),
9960
10002
  roles: resolved.roles,
9961
10003
  permissions: resolved.permissions,
9962
10004
  claims: resolved.claims
@@ -9966,7 +10008,7 @@ var AuthoritiesContextBuilder = class {
9966
10008
  relationships: this.relationshipResolver
9967
10009
  };
9968
10010
  }
9969
- const user = authInfo?.user ?? {};
10011
+ const user = resolveAuthUser(authInfo);
9970
10012
  const authorization = authInfo?.extra?.["authorization"];
9971
10013
  const authorizationClaims = authorization?.["claims"] ?? {};
9972
10014
  const rawClaims = {
@@ -9987,10 +10029,10 @@ var AuthoritiesContextBuilder = class {
9987
10029
  } else {
9988
10030
  permissions = toStringArray(user["permissions"] ?? []);
9989
10031
  }
9990
- const sub = this.claimsMapping?.userId ? String(resolveDotPath(rawClaims, this.claimsMapping.userId) ?? "") : user.sub ?? "";
10032
+ const mappedSub = this.claimsMapping?.userId ? resolveDotPath(rawClaims, this.claimsMapping.userId) : void 0;
9991
10033
  return {
9992
10034
  user: {
9993
- sub,
10035
+ sub: signedInSubject(user.sub, mappedSub),
9994
10036
  roles,
9995
10037
  permissions,
9996
10038
  claims: rawClaims
@@ -10022,15 +10064,17 @@ var FrontMcpAuthContextImpl = class {
10022
10064
  roles;
10023
10065
  permissions;
10024
10066
  constructor(source, claimsMapping) {
10025
- const rawUser = source.user ?? {};
10026
- const sub = claimsMapping?.userId ? String(resolveDotPath(this.buildRawClaims(source), claimsMapping.userId) ?? rawUser.sub ?? "") : String(rawUser.sub ?? "");
10067
+ const rawUser = resolveAuthUser(source);
10068
+ const mappedSub = claimsMapping?.userId ? resolveDotPath(this.buildRawClaims(source), claimsMapping.userId) : void 0;
10069
+ const signedInSub = signedInSubject(rawUser.sub, mappedSub);
10070
+ const sub = signedInSub ?? (typeof rawUser.sub === "string" ? rawUser.sub : "");
10027
10071
  this.user = Object.freeze({
10028
10072
  sub,
10029
10073
  name: rawUser.name,
10030
10074
  email: rawUser.email,
10031
10075
  picture: rawUser.picture
10032
10076
  });
10033
- this.isAnonymous = sub === "" || sub.startsWith("anon:");
10077
+ this.isAnonymous = signedInSub === void 0;
10034
10078
  const extraAuth = source.extra?.["authorization"];
10035
10079
  this.mode = String(
10036
10080
  source.extra?.["authMode"] ?? extraAuth?.["mode"] ?? (source.extra?.["isPublic"] === true || rawUser["anonymous"] === true ? "public" : "authenticated")
@@ -10088,7 +10132,7 @@ var FrontMcpAuthContextImpl = class {
10088
10132
  * Mirrors the logic in AuthoritiesContextBuilder.build().
10089
10133
  */
10090
10134
  buildRawClaims(source) {
10091
- const rawUser = source.user ?? {};
10135
+ const rawUser = resolveAuthUser(source);
10092
10136
  const extraAuth = source.extra?.["authorization"];
10093
10137
  const authorizationClaims = extraAuth?.["claims"] ?? {};
10094
10138
  return {
@@ -10153,20 +10197,20 @@ function resolveRequiredScopes(denial, mapping, authorities) {
10153
10197
  }
10154
10198
 
10155
10199
  // libs/auth/src/authorities/authorities.schema.ts
10156
- import { z as z19 } from "@frontmcp/lazy-zod";
10157
- var rbacRolesPolicySchema = z19.object({
10158
- all: z19.array(z19.string().min(1)).optional(),
10159
- any: z19.array(z19.string().min(1)).optional()
10200
+ import { z as z20 } from "@frontmcp/lazy-zod";
10201
+ var rbacRolesPolicySchema = z20.object({
10202
+ all: z20.array(z20.string().min(1)).optional(),
10203
+ any: z20.array(z20.string().min(1)).optional()
10160
10204
  }).refine((data) => data.all !== void 0 || data.any !== void 0, {
10161
10205
  message: 'Roles policy must have at least "all" or "any"'
10162
10206
  });
10163
- var rbacPermissionsPolicySchema = z19.object({
10164
- all: z19.array(z19.string().min(1)).optional(),
10165
- any: z19.array(z19.string().min(1)).optional()
10207
+ var rbacPermissionsPolicySchema = z20.object({
10208
+ all: z20.array(z20.string().min(1)).optional(),
10209
+ any: z20.array(z20.string().min(1)).optional()
10166
10210
  }).refine((data) => data.all !== void 0 || data.any !== void 0, {
10167
10211
  message: 'Permissions policy must have at least "all" or "any"'
10168
10212
  });
10169
- var abacOperatorSchema = z19.enum([
10213
+ var abacOperatorSchema = z20.enum([
10170
10214
  "eq",
10171
10215
  "neq",
10172
10216
  "in",
@@ -10181,55 +10225,55 @@ var abacOperatorSchema = z19.enum([
10181
10225
  "exists",
10182
10226
  "matches"
10183
10227
  ]);
10184
- var abacConditionSchema = z19.object({
10185
- path: z19.string().min(1),
10228
+ var abacConditionSchema = z20.object({
10229
+ path: z20.string().min(1),
10186
10230
  op: abacOperatorSchema,
10187
- value: z19.unknown()
10231
+ value: z20.unknown()
10188
10232
  });
10189
- var abacPolicySchema = z19.object({
10190
- match: z19.record(z19.string(), z19.unknown()).optional(),
10191
- conditions: z19.array(abacConditionSchema).optional()
10233
+ var abacPolicySchema = z20.object({
10234
+ match: z20.record(z20.string(), z20.unknown()).optional(),
10235
+ conditions: z20.array(abacConditionSchema).optional()
10192
10236
  }).refine((data) => data.match !== void 0 || data.conditions !== void 0, {
10193
10237
  message: 'Attributes policy must have at least "match" or "conditions"'
10194
10238
  });
10195
- var resourceIdRefSchema = z19.union([
10196
- z19.string().min(1),
10197
- z19.object({ fromInput: z19.string().min(1) }).strict(),
10198
- z19.object({ fromClaims: z19.string().min(1) }).strict()
10239
+ var resourceIdRefSchema = z20.union([
10240
+ z20.string().min(1),
10241
+ z20.object({ fromInput: z20.string().min(1) }).strict(),
10242
+ z20.object({ fromClaims: z20.string().min(1) }).strict()
10199
10243
  ]);
10200
- var rebacPolicySchema = z19.object({
10201
- type: z19.string().min(1),
10202
- resource: z19.string().min(1),
10244
+ var rebacPolicySchema = z20.object({
10245
+ type: z20.string().min(1),
10246
+ resource: z20.string().min(1),
10203
10247
  resourceId: resourceIdRefSchema
10204
10248
  });
10205
10249
  var basePolicyShape = {
10206
10250
  roles: rbacRolesPolicySchema.optional(),
10207
10251
  permissions: rbacPermissionsPolicySchema.optional(),
10208
10252
  attributes: abacPolicySchema.optional(),
10209
- relationships: z19.union([rebacPolicySchema, z19.array(rebacPolicySchema)]).optional(),
10210
- custom: z19.record(z19.string(), z19.unknown()).optional(),
10211
- guards: z19.array(z19.instanceof(Function)).optional(),
10212
- operator: z19.enum(["AND", "OR"]).optional()
10253
+ relationships: z20.union([rebacPolicySchema, z20.array(rebacPolicySchema)]).optional(),
10254
+ custom: z20.record(z20.string(), z20.unknown()).optional(),
10255
+ guards: z20.array(z20.instanceof(Function)).optional(),
10256
+ operator: z20.enum(["AND", "OR"]).optional()
10213
10257
  };
10214
- var authoritiesPolicySchema = z19.lazy(
10215
- () => z19.object({
10258
+ var authoritiesPolicySchema = z20.lazy(
10259
+ () => z20.object({
10216
10260
  ...basePolicyShape,
10217
10261
  not: authoritiesPolicySchema.optional(),
10218
- anyOf: z19.array(authoritiesPolicySchema).optional(),
10219
- allOf: z19.array(authoritiesPolicySchema).optional()
10262
+ anyOf: z20.array(authoritiesPolicySchema).optional(),
10263
+ allOf: z20.array(authoritiesPolicySchema).optional()
10220
10264
  })
10221
10265
  );
10222
- var authoritiesMetadataSchema = z19.union([
10223
- z19.string().min(1),
10224
- z19.array(z19.string().min(1)).min(1),
10266
+ var authoritiesMetadataSchema = z20.union([
10267
+ z20.string().min(1),
10268
+ z20.array(z20.string().min(1)).min(1),
10225
10269
  authoritiesPolicySchema
10226
10270
  ]);
10227
- var authoritiesClaimsMappingSchema = z19.record(z19.string(), z19.string().optional()).refine((data) => Object.values(data).some((v) => v !== void 0), {
10271
+ var authoritiesClaimsMappingSchema = z20.record(z20.string(), z20.string().optional()).refine((data) => Object.values(data).some((v) => v !== void 0), {
10228
10272
  message: "Claims mapping must have at least one mapping"
10229
10273
  });
10230
- var authoritiesConfigSchema = z19.object({
10274
+ var authoritiesConfigSchema = z20.object({
10231
10275
  claimsMapping: authoritiesClaimsMappingSchema.optional(),
10232
- profiles: z19.record(z19.string().min(1), authoritiesPolicySchema).optional()
10276
+ profiles: z20.record(z20.string().min(1), authoritiesPolicySchema).optional()
10233
10277
  });
10234
10278
 
10235
10279
  // libs/auth/src/authorities/authorities.evaluator.ts
@@ -10307,8 +10351,9 @@ function resolveValue(value, ctx) {
10307
10351
  }
10308
10352
  function applyOperator(actual, op, expected) {
10309
10353
  switch (op) {
10354
+ // A missing expected value (e.g. an absent fromInput) never matches, even an absent actual value
10310
10355
  case "eq":
10311
- return actual === expected;
10356
+ return expected !== void 0 && actual === expected;
10312
10357
  case "neq":
10313
10358
  return actual !== expected;
10314
10359
  case "in":
@@ -10357,7 +10402,7 @@ function evaluateAbac(policy, ctx) {
10357
10402
  for (const [path, expectedRaw] of Object.entries(policy.match)) {
10358
10403
  const actual = resolveDotPath(envelope, path);
10359
10404
  const expected = resolveValue(expectedRaw, ctx);
10360
- if (actual !== expected) {
10405
+ if (expected === void 0 || actual !== expected) {
10361
10406
  return {
10362
10407
  granted: false,
10363
10408
  deniedBy: `attributes.match: '${path}' expected '${String(expected)}' but got '${String(actual)}'`,
@@ -10397,6 +10442,15 @@ function resolveResourceId(ref, ctx) {
10397
10442
  return void 0;
10398
10443
  }
10399
10444
  async function evaluateSingleRebac(policy, ctx) {
10445
+ const userSub = ctx.user.sub;
10446
+ if (userSub === void 0 || isAnonymousSubject(userSub)) {
10447
+ return {
10448
+ granted: false,
10449
+ deniedBy: `relationships: an anonymous caller cannot be '${policy.type}' of ${policy.resource}`,
10450
+ denial: { kind: "relationships", path: "user.sub", expected: "a signed-in caller", actual: void 0 },
10451
+ evaluatedPolicies: ["relationships"]
10452
+ };
10453
+ }
10400
10454
  const resourceId = resolveResourceId(policy.resourceId, ctx);
10401
10455
  if (resourceId === void 0) {
10402
10456
  return {
@@ -10411,11 +10465,11 @@ async function evaluateSingleRebac(policy, ctx) {
10411
10465
  evaluatedPolicies: ["relationships"]
10412
10466
  };
10413
10467
  }
10414
- const hasRelationship = await ctx.relationships.check(policy.type, policy.resource, resourceId, ctx.user.sub, ctx);
10468
+ const hasRelationship = await ctx.relationships.check(policy.type, policy.resource, resourceId, userSub, ctx);
10415
10469
  if (!hasRelationship) {
10416
10470
  return {
10417
10471
  granted: false,
10418
- deniedBy: `relationships: user '${ctx.user.sub}' is not '${policy.type}' of ${policy.resource}:${resourceId}`,
10472
+ deniedBy: `relationships: user '${userSub}' is not '${policy.type}' of ${policy.resource}:${resourceId}`,
10419
10473
  denial: {
10420
10474
  kind: "relationships",
10421
10475
  path: "relationships",
@@ -10932,6 +10986,8 @@ export {
10932
10986
  InMemoryStoreRequiredError,
10933
10987
  InvalidClientIdUrlError,
10934
10988
  JwksService,
10989
+ JwtSecretRequiredError,
10990
+ JwtSecretWeakError,
10935
10991
  LazyCredentialLoader,
10936
10992
  NoProviderIdError,
10937
10993
  NullOrchestratedAuthAccessor,
@@ -11086,6 +11142,7 @@ export {
11086
11142
  headerApplier,
11087
11143
  hkdfSha2564 as hkdfSha256,
11088
11144
  incrementalAuthConfigSchema,
11145
+ isAnonymousSubject,
11089
11146
  isCimdClientId,
11090
11147
  isFrontMcpCredentials,
11091
11148
  isJwt,
@@ -11102,6 +11159,7 @@ export {
11102
11159
  isSoonExpiring,
11103
11160
  isSoonExpiringProvider,
11104
11161
  isSqliteTokenStorage,
11162
+ isStaticMode,
11105
11163
  isTransparentMode,
11106
11164
  jsonWebKeySetSchema,
11107
11165
  jwkParametersSchema,
@@ -11161,6 +11219,7 @@ export {
11161
11219
  startNextProvider,
11162
11220
  statefulHttpTransportStateSchema,
11163
11221
  statelessHttpTransportStateSchema,
11222
+ staticAuthOptionsSchema,
11164
11223
  storedSessionSchema,
11165
11224
  streamableHttpTransportStateSchema,
11166
11225
  toEpochSeconds,