@frontmcp/auth 1.5.3 → 1.5.5

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.
@@ -39,6 +39,15 @@ export interface DcrRegistryConfig {
39
39
  allowedClientIds?: string[];
40
40
  initialAccessToken?: string;
41
41
  clients?: PreRegisteredClientInput[];
42
+ /**
43
+ * Maximum number of DYNAMICALLY-registered (DCR) clients kept in memory.
44
+ * Once the cap is reached, further dynamic registrations are REJECTED (rather
45
+ * than evicting an existing client), so every already-registered client —
46
+ * including confidential ones — is preserved. Pre-registered / declarative
47
+ * clients never count toward this cap and are never rejected. Defaults to
48
+ * 1000. Guards against unbounded growth from unauthenticated DCR.
49
+ */
50
+ maxDynamicClients?: number;
42
51
  }
43
52
  /**
44
53
  * Local-AS DCR client registry. Seeded from `dcr.clients` at construction and
@@ -47,16 +56,52 @@ export interface DcrRegistryConfig {
47
56
  export declare class DcrClientRegistry {
48
57
  private readonly config;
49
58
  private readonly clients;
50
- private readonly redirectMatchers;
59
+ /** Configured redirect_uri allowlist globs (matched via `globMatch`). */
60
+ private readonly redirectGlobs;
51
61
  constructor(config?: DcrRegistryConfig);
52
62
  /** Seed `dcr.clients` so the authorize/token flows accept them without DCR. */
53
63
  private seedPreRegisteredClients;
54
64
  /** Look up a client by id (pre-registered or dynamically registered). */
55
65
  get(clientId: string): RegisteredClient | undefined;
66
+ /**
67
+ * Authenticate a client at the token endpoint (RFC 6749 §2.3 / §3.2.1).
68
+ *
69
+ * - `'unknown'` — the client id is not registered (caller decides; today's
70
+ * public / CIMD clients are unregistered and treated as "no secret to
71
+ * verify").
72
+ * - `'ok'` — public client (`none`), or a confidential client whose
73
+ * presented secret matched (constant-time).
74
+ * - `'invalid'` — a confidential client with a missing or wrong secret. The
75
+ * caller MUST reject with `invalid_client`.
76
+ *
77
+ * SECURITY: previously the token endpoint verified only `client_id` equality,
78
+ * so a DCR-minted `client_secret` was never checked and a "confidential"
79
+ * client was effectively public. This restores confidential-client
80
+ * authentication with a timing-safe comparison.
81
+ */
82
+ verifyClientSecret(clientId: string, presentedSecret: string | undefined): 'unknown' | 'ok' | 'invalid';
56
83
  /** Whether a client id is known to the registry. */
57
84
  has(clientId: string): boolean;
58
- /** Add a dynamically-registered client (called by the register flow). */
59
- register(client: RegisteredClient): void;
85
+ /**
86
+ * Add a dynamically-registered client (called by the register flow).
87
+ *
88
+ * @returns `true` if the client was registered, `false` if the dynamic-client
89
+ * capacity is already reached.
90
+ *
91
+ * SECURITY: `POST /oauth/register` may be unauthenticated (no
92
+ * `initialAccessToken`); without a bound an attacker can register unlimited
93
+ * clients and exhaust memory. Once the cap is reached we REJECT new dynamic
94
+ * registrations rather than evicting an existing one — this preserves every
95
+ * already-registered client (including confidential ones with a
96
+ * `client_secret`), which eviction would have silently invalidated. The
97
+ * register flow surfaces `false` as a `temporarily_unavailable` error.
98
+ * Pre-registered / declarative clients are exempt and never count toward the
99
+ * cap.
100
+ */
101
+ register(client: RegisteredClient): boolean;
102
+ /** Configured dynamic-client cap, falling back to the default when invalid. */
103
+ private dynamicClientCap;
104
+ private countDynamicClients;
60
105
  /** Whether a redirect_uri allowlist is configured. */
61
106
  hasRedirectAllowlist(): boolean;
62
107
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dcr-client.registry.d.ts","sourceRoot":"","sources":["../../src/authorization/dcr-client.registry.ts"],"names":[],"mappings":"AAgBA,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0BAA0B,EACtB,MAAM,GACN,qBAAqB,GACrB,oBAAoB,GACpB,iBAAiB,GACjB,iBAAiB,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,GAAG,EAAE,OAAO,CAAC;IACb,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uBAAuB,CAAC,EAAE,MAAM,GAAG,qBAAqB,GAAG,oBAAoB,CAAC;IAChF,UAAU,CAAC,EAAE,KAAK,CAAC,oBAAoB,GAAG,eAAe,CAAC,CAAC;IAC3D,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,2DAA2D;AAC3D,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,wBAAwB,EAAE,CAAC;CACtC;AAaD;;;GAGG;AACH,qBAAa,iBAAiB;IAIhB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuB;gBAE3B,MAAM,GAAE,iBAAsB;IAK3D,+EAA+E;IAC/E,OAAO,CAAC,wBAAwB;IAoBhC,yEAAyE;IACzE,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAInD,oDAAoD;IACpD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI9B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAIxC,sDAAsD;IACtD,oBAAoB,IAAI,OAAO;IAI/B;;;OAGG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAOlD,mDAAmD;IACnD,oBAAoB,IAAI,OAAO;IAI/B;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQ5C,wEAAwE;IACxE,0BAA0B,IAAI,OAAO;IAIrC;;;;OAIG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO;CAajE"}
1
+ {"version":3,"file":"dcr-client.registry.d.ts","sourceRoot":"","sources":["../../src/authorization/dcr-client.registry.ts"],"names":[],"mappings":"AAgBA,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0BAA0B,EACtB,MAAM,GACN,qBAAqB,GACrB,oBAAoB,GACpB,iBAAiB,GACjB,iBAAiB,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,GAAG,EAAE,OAAO,CAAC;IACb,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uBAAuB,CAAC,EAAE,MAAM,GAAG,qBAAqB,GAAG,oBAAoB,CAAC;IAChF,UAAU,CAAC,EAAE,KAAK,CAAC,oBAAoB,GAAG,eAAe,CAAC,CAAC;IAC3D,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,2DAA2D;AAC3D,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,wBAAwB,EAAE,CAAC;IACrC;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAoHD;;;GAGG;AACH,qBAAa,iBAAiB;IAKhB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;gBAExB,MAAM,GAAE,iBAAsB;IAK3D,+EAA+E;IAC/E,OAAO,CAAC,wBAAwB;IAoBhC,yEAAyE;IACzE,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAInD;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS;IAcvG,oDAAoD;IACpD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI9B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO;IAY3C,+EAA+E;IAC/E,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,mBAAmB;IAM3B,sDAAsD;IACtD,oBAAoB,IAAI,OAAO;IAI/B;;;OAGG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAOlD,mDAAmD;IACnD,oBAAoB,IAAI,OAAO;IAI/B;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQ5C,wEAAwE;IACxE,0BAA0B,IAAI,OAAO;IAIrC;;;;OAIG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO;CAajE"}
@@ -1 +1 @@
1
- {"version":3,"file":"cimd.service.d.ts","sourceRoot":"","sources":["../../src/cimd/cimd.service.ts"],"names":[],"mappings":"AAeA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAQL,KAAK,eAAe,EAEpB,KAAK,oBAAoB,EAEzB,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;AAGtB;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;OAKG;gBACS,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IA4BlE;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIzC;;;;;;;;OAQG;IACG,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAoD5E;;;;;;OAMG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAUhF;;;;OAIG;IACG,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAMhD;;;;OAIG;YACW,qBAAqB;IAmJnC;;OAEG;YACW,qBAAqB;IAyCnC;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;CAiBzB"}
1
+ {"version":3,"file":"cimd.service.d.ts","sourceRoot":"","sources":["../../src/cimd/cimd.service.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAQL,KAAK,eAAe,EAEpB,KAAK,oBAAoB,EAEzB,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;AAGtB;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;OAKG;gBACS,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IA4BlE;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIzC;;;;;;;;OAQG;IACG,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAoD5E;;;;;;OAMG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAUhF;;;;OAIG;IACG,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAMhD;;;;OAIG;YACW,qBAAqB;IAoKnC;;OAEG;YACW,qBAAqB;IAyCnC;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;CAiBzB"}
@@ -35,6 +35,38 @@ interface SsrfCheckResult {
35
35
  * @returns Result indicating if the hostname is allowed
36
36
  */
37
37
  export declare function checkSsrfProtection(hostname: string): SsrfCheckResult;
38
+ /**
39
+ * Resolve a hostname via DNS and validate EVERY resolved address against the
40
+ * private/reserved-range blocklist — the DNS-aware complement to
41
+ * {@link checkSsrfProtection}.
42
+ *
43
+ * SECURITY (SSRF): `checkSsrfProtection` alone only inspects literal-IP and
44
+ * localhost-string hostnames; a hostname like `metadata.attacker.example` whose
45
+ * A-record points at `169.254.169.254` / `10.x` / `127.x` passes it untouched
46
+ * and the subsequent `fetch()` then connects to the internal address. This
47
+ * function closes that gap by resolving the name and rejecting if ANY resolved
48
+ * address is internal.
49
+ *
50
+ * Residual risk (documented, not yet closed here): DNS rebinding — the resolver
51
+ * used here and the resolver used by `fetch()` are distinct, so a TOCTOU
52
+ * attacker could return a public IP to this check and an internal IP to the
53
+ * fetch. Fully closing it requires pinning the socket to the validated IP
54
+ * (custom undici `lookup`/dispatcher), which is left to the caller/runtime.
55
+ *
56
+ * Degrades gracefully when `node:dns` is unavailable (e.g. a V8-isolate runtime)
57
+ * or the name fails to resolve: an unresolvable name cannot be reached by
58
+ * `fetch()` either, so we fall back to the literal-IP checks that already ran.
59
+ */
60
+ export declare function resolveAndCheckHostname(hostname: string): Promise<SsrfCheckResult>;
61
+ /**
62
+ * Throwing wrapper around {@link resolveAndCheckHostname} for CIMD fetch paths.
63
+ * Must be called immediately before each outbound `fetch` (initial URL AND every
64
+ * redirect hop) so an attacker-supplied `client_id` host cannot resolve to an
65
+ * internal address.
66
+ *
67
+ * @throws CimdSecurityError if the host (or any resolved address) is internal.
68
+ */
69
+ export declare function assertHostNotSsrf(hostname: string, clientId: string): Promise<void>;
38
70
  /**
39
71
  * Check if any redirect URIs in the list are localhost-only.
40
72
  *
@@ -1 +1 @@
1
- {"version":3,"file":"cimd.validator.d.ts","sourceRoot":"","sources":["../../src/cimd/cimd.validator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,OAAO,CA4B/E;AAUD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,GAAG,CA6DvG;AAED;;GAEG;AACH,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAqBrE;AAqKD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAgB5E"}
1
+ {"version":3,"file":"cimd.validator.d.ts","sourceRoot":"","sources":["../../src/cimd/cimd.validator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,OAAO,CA4B/E;AAUD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,GAAG,CA6DvG;AAED;;GAEG;AACH,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAqBrE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAgDxF;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzF;AAgLD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAgB5E"}