@aooth/auth 0.1.47 → 0.1.48

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 (33) hide show
  1. package/dist/atscript-db.cjs +3 -1
  2. package/dist/atscript-db.d.cts +4 -3
  3. package/dist/atscript-db.d.mts +4 -3
  4. package/dist/atscript-db.mjs +3 -1
  5. package/dist/auth-credential-C3qebKuy.d.mts +245 -0
  6. package/dist/auth-credential-CEijxoGU.d.cts +245 -0
  7. package/dist/authz.cjs +124 -35
  8. package/dist/authz.d.cts +78 -24
  9. package/dist/authz.d.mts +78 -24
  10. package/dist/authz.mjs +121 -37
  11. package/dist/{store-BG6m6oSJ.d.mts → clock-DJ_eroHW.d.cts} +50 -1
  12. package/dist/{store-BG6m6oSJ.d.cts → clock-DJ_eroHW.d.mts} +50 -1
  13. package/dist/{dynamic-client-store-DLRfntHr.mjs → dynamic-client-store-B1JwFHdP.mjs} +1 -0
  14. package/dist/{dynamic-client-store-DzqdUwnw.d.cts → dynamic-client-store-DJgtMjPw.d.mts} +58 -9
  15. package/dist/{dynamic-client-store-oHEsQaJg.d.mts → dynamic-client-store-DbiSLOj0.d.cts} +58 -9
  16. package/dist/{dynamic-client-store-DAStgv2j.cjs → dynamic-client-store-DykM9QOT.cjs} +1 -0
  17. package/dist/index.cjs +39 -26
  18. package/dist/index.d.cts +12 -218
  19. package/dist/index.d.mts +12 -218
  20. package/dist/index.mjs +39 -27
  21. package/dist/opaque-token-BaMOrC1A.mjs +13 -0
  22. package/dist/opaque-token-CaZgD2i6.cjs +18 -0
  23. package/dist/redis.d.cts +2 -2
  24. package/dist/redis.d.mts +2 -2
  25. package/dist/{store-N9daSmHS.d.cts → store-BYnpA7VK.d.cts} +1 -1
  26. package/dist/{store-jFgby4bK.d.mts → store-pKh0ZaGG.d.mts} +1 -1
  27. package/package.json +2 -2
  28. package/src/atscript-db/auth-credential.as +16 -0
  29. package/src/atscript-db/auth-credential.as.d.ts +4 -1
  30. package/src/atscript-db/dynamic-client.as +11 -1
  31. package/src/atscript-db/dynamic-client.as.d.ts +3 -0
  32. package/dist/clock-BjXa0LXb.d.cts +0 -14
  33. package/dist/clock-BjXa0LXb.d.mts +0 -14
package/dist/authz.cjs CHANGED
@@ -1,8 +1,38 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_clock = require("./clock-Bl-H3eqE.cjs");
3
- const require_dynamic_client_store = require("./dynamic-client-store-DAStgv2j.cjs");
3
+ const require_opaque_token = require("./opaque-token-CaZgD2i6.cjs");
4
+ const require_dynamic_client_store = require("./dynamic-client-store-DykM9QOT.cjs");
4
5
  let node_crypto = require("node:crypto");
5
6
  let jose = require("jose");
7
+ //#region src/authz/token-policy.ts
8
+ /**
9
+ * Default refresh-token (grant) lifetime for {@link TokenPolicy.refresh} when
10
+ * no `ttl` is given: 30 days. Deliberately independent of the session tier's
11
+ * `AuthCredentialOptions.refresh.ttl` — an authz grant's lifetime is the
12
+ * policy's decision, never inherited from browser-session posture.
13
+ */
14
+ const DEFAULT_AUTHZ_REFRESH_TTL_MS = 720 * 60 * 6e4;
15
+ /**
16
+ * Flatten a {@link TokenPolicy} into the `AuthCredential.issue()` options a
17
+ * token endpoint forwards. The refresh dimension applies only to client-bound
18
+ * grants — the family is stamped with `metadata.authzClientId`, the binding
19
+ * the `refresh_token` grant enforces — so a clientless (loopback) grant
20
+ * ignores `policy.refresh`. `refresh: false` otherwise: an authz mint never
21
+ * rides the instance-level session refresh config (no orphaned refresh row
22
+ * for a policy that didn't opt in). Lives HERE, next to the policy type and
23
+ * its default ttl, so every HTTP adapter applies the same semantics.
24
+ */
25
+ function tokenPolicyToIssueOptions(policy, clientId) {
26
+ const withRefresh = policy.refresh !== void 0 && clientId !== void 0;
27
+ return {
28
+ ...policy.payload,
29
+ ...policy.kind !== void 0 && { kind: policy.kind },
30
+ ...policy.ttl !== void 0 && { ttl: policy.ttl },
31
+ refresh: withRefresh ? { ttl: policy.refresh?.ttl ?? 2592e6 } : false,
32
+ ...withRefresh && { metadata: { authzClientId: clientId } }
33
+ };
34
+ }
35
+ //#endregion
6
36
  //#region src/authz/authz-errors.ts
7
37
  /** A typed authorization-server failure. */
8
38
  var AuthorizeError = class extends Error {
@@ -60,6 +90,15 @@ var LoopbackClientPolicy = class {
60
90
  }
61
91
  };
62
92
  //#endregion
93
+ //#region src/utils/timing-safe.ts
94
+ /** Constant-time string compare that also fails closed on a length mismatch. */
95
+ function timingSafeEqualStr(a, b) {
96
+ const ab = Buffer.from(a, "utf8");
97
+ const bb = Buffer.from(b, "utf8");
98
+ if (ab.length !== bb.length) return false;
99
+ return (0, node_crypto.timingSafeEqual)(ab, bb);
100
+ }
101
+ //#endregion
63
102
  //#region src/authz/oidc-claims-resolver.ts
64
103
  /**
65
104
  * Resolves the OIDC profile claims to embed in an `id_token` for a given user +
@@ -157,13 +196,6 @@ var RegisteredClientPolicy = class {
157
196
  return granted.length > 0 ? granted.join(" ") : void 0;
158
197
  }
159
198
  };
160
- /** Constant-time string compare that also fails closed on a length mismatch. */
161
- function timingSafeEqualStr(a, b) {
162
- const ab = Buffer.from(a, "utf8");
163
- const bb = Buffer.from(b, "utf8");
164
- if (ab.length !== bb.length) return false;
165
- return (0, node_crypto.timingSafeEqual)(ab, bb);
166
- }
167
199
  //#endregion
168
200
  //#region src/authz/composite-client-policy.ts
169
201
  /**
@@ -213,6 +245,30 @@ var CompositeClientPolicy = class {
213
245
  }
214
246
  };
215
247
  //#endregion
248
+ //#region src/authz/client-secret.ts
249
+ /**
250
+ * Mint a confidential dynamic client's secret (RFC 7591 `client_secret`) — a
251
+ * plain {@link generateOpaqueToken} mint. Returned to the registrant ONCE in
252
+ * the registration response; only its {@link hashClientSecret} digest is
253
+ * stored.
254
+ */
255
+ function mintClientSecret() {
256
+ return require_opaque_token.generateOpaqueToken();
257
+ }
258
+ /**
259
+ * Storage digest for a client secret — plain SHA-256 (hex). No KDF/salt on
260
+ * purpose: the secret is high-entropy server-minted material (never a human
261
+ * password), so brute-forcing the digest is infeasible and a per-row salt
262
+ * buys nothing.
263
+ */
264
+ function hashClientSecret(secret) {
265
+ return (0, node_crypto.createHash)("sha256").update(secret, "utf8").digest("hex");
266
+ }
267
+ /** Constant-time check of a presented secret against a stored digest. */
268
+ function verifyClientSecret(secret, hash) {
269
+ return timingSafeEqualStr(hashClientSecret(secret), hash);
270
+ }
271
+ //#endregion
216
272
  //#region src/authz/client-registration.ts
217
273
  /** A typed RFC 7591 registration failure; `message` becomes `error_description`. */
218
274
  var ClientRegistrationError = class extends Error {
@@ -223,9 +279,11 @@ var ClientRegistrationError = class extends Error {
223
279
  this.code = code;
224
280
  }
225
281
  };
226
- /** Grant/response types the v1 authorization server supports (auth-code + PKCE only). */
227
- const SUPPORTED_GRANT_TYPES = ["authorization_code"];
282
+ /** Grant/response types the authorization server supports (auth-code + PKCE, plus refresh). */
283
+ const SUPPORTED_GRANT_TYPES = ["authorization_code", "refresh_token"];
228
284
  const SUPPORTED_RESPONSE_TYPES = ["code"];
285
+ /** Token-endpoint auth methods DCR accepts (both advertised in the RFC 8414 document). */
286
+ const SUPPORTED_TOKEN_ENDPOINT_AUTH_METHODS = ["none", "client_secret_post"];
229
287
  /** RFC 6749 §3.3 scope-token charset: printable ASCII minus space, `"` and `\`. */
230
288
  const SCOPE_TOKEN_RE = /^[\x21\x23-\x5B\x5D-\x7E]+$/u;
231
289
  const DEFAULT_MAX_REDIRECT_URIS = 5;
@@ -274,13 +332,14 @@ function isAcceptableRedirectUri(uri) {
274
332
  * Normalization is allowed by RFC 7591 §2 (the server MAY replace requested
275
333
  * metadata with its own values) and is load-bearing for real connectors:
276
334
  * `grant_types` / `response_types` are INTERSECTED with what the server
277
- * supports (a connector requesting `["authorization_code", "refresh_token"]`
278
- * registers with `["authorization_code"]` — the 201 echo of the narrowed set
279
- * is the contract) rather than rejected. `token_endpoint_auth_method` defaults
280
- * to `"none"` when absent (v1 is public-clients-only, so the RFC's
281
- * `client_secret_basic` default is unsupported), but an EXPLICIT non-`"none"`
282
- * ask is rejected — never silently downgrade a client that asked for a secret.
283
- * Unknown fields are ignored and never echoed.
335
+ * supports (an unsupported grant is dropped from the echo — the 201 echo of
336
+ * the narrowed set is the contract) rather than rejected, but the result must
337
+ * still include `authorization_code` (it is the only way to establish a grant;
338
+ * `refresh_token` alone mints nothing). `token_endpoint_auth_method` defaults
339
+ * to `"none"` when absent (the RFC's `client_secret_basic` default is
340
+ * unsupported — secrets travel in the POST form body); an EXPLICIT ask outside
341
+ * the allowed set is rejected — never silently downgrade a client that asked
342
+ * for a secret. Unknown fields are ignored and never echoed.
284
343
  */
285
344
  function validateClientRegistration(body, opts) {
286
345
  if (typeof body !== "object" || body === null || Array.isArray(body)) throw new ClientRegistrationError("invalid_client_metadata", "registration request must be a JSON object");
@@ -292,9 +351,11 @@ function validateClientRegistration(body, opts) {
292
351
  if (redirectUris.length === 0) throw new ClientRegistrationError("invalid_redirect_uri", "redirect_uris must be non-empty");
293
352
  if (redirectUris.length > maxUris) throw new ClientRegistrationError("invalid_redirect_uri", `redirect_uris accepts at most ${maxUris} entries`);
294
353
  for (const uri of redirectUris) if (uri.length > maxUriLength || !isAcceptableRedirectUri(uri)) throw new ClientRegistrationError("invalid_redirect_uri", "each redirect_uri must be an https URL with an explicit host or a loopback literal, without a fragment");
295
- if ((req.token_endpoint_auth_method ?? "none") !== "none") throw new ClientRegistrationError("invalid_client_metadata", "only token_endpoint_auth_method \"none\" is supported");
354
+ const allowedAuthMethods = (opts?.allowedTokenEndpointAuthMethods ?? SUPPORTED_TOKEN_ENDPOINT_AUTH_METHODS).filter((m) => SUPPORTED_TOKEN_ENDPOINT_AUTH_METHODS.includes(m));
355
+ const authMethod = req.token_endpoint_auth_method ?? "none";
356
+ if (typeof authMethod !== "string" || !allowedAuthMethods.includes(authMethod)) throw new ClientRegistrationError("invalid_client_metadata", `only token_endpoint_auth_method ${allowedAuthMethods.map((m) => `"${m}"`).join(" / ")} is supported`);
296
357
  const grantTypes = req.grant_types === void 0 ? [...SUPPORTED_GRANT_TYPES] : asStringArray(req.grant_types, "grant_types").filter((g) => SUPPORTED_GRANT_TYPES.includes(g));
297
- if (grantTypes.length === 0) throw new ClientRegistrationError("invalid_client_metadata", "grant_types must include authorization_code");
358
+ if (!grantTypes.includes("authorization_code")) throw new ClientRegistrationError("invalid_client_metadata", "grant_types must include authorization_code");
298
359
  const responseTypes = req.response_types === void 0 ? [...SUPPORTED_RESPONSE_TYPES] : asStringArray(req.response_types, "response_types").filter((r) => SUPPORTED_RESPONSE_TYPES.includes(r));
299
360
  if (responseTypes.length === 0) throw new ClientRegistrationError("invalid_client_metadata", "response_types must include code");
300
361
  let clientName;
@@ -313,7 +374,7 @@ function validateClientRegistration(body, opts) {
313
374
  }
314
375
  return {
315
376
  redirectUris,
316
- tokenEndpointAuthMethod: "none",
377
+ tokenEndpointAuthMethod: authMethod,
317
378
  grantTypes,
318
379
  responseTypes,
319
380
  ...clientName !== void 0 && { clientName },
@@ -324,9 +385,9 @@ const DEFAULT_MAX_CLIENTS = 1e3;
324
385
  /**
325
386
  * The RFC 7591 registration operation behind `POST {issuer}/register`
326
387
  * (OAUTH.md R2): validate → guard → lazy GC of never-used rows → hard cap →
327
- * persist. Framework-free — `@aooth/auth-moost`'s controller endpoint is a
328
- * thin HTTP adapter over `register()`, and non-moost servers can call it
329
- * directly.
388
+ * mint secret (confidential) → persist. Framework-free — `@aooth/auth-moost`'s
389
+ * controller endpoint is a thin HTTP adapter over `register()`, and non-moost
390
+ * servers can call it directly.
330
391
  */
331
392
  var DynamicClientRegistration = class {
332
393
  store;
@@ -343,12 +404,28 @@ var DynamicClientRegistration = class {
343
404
  this.validation = opts.validation;
344
405
  this.clock = opts.clock ?? require_clock.defaultClock;
345
406
  }
346
- /** Validate and persist a registration request body; returns the minted client. */
407
+ /**
408
+ * Validate and persist a registration request body; returns the minted
409
+ * client. For a `client_secret_post` registration the returned record
410
+ * additionally carries the plaintext `clientSecret` (the ONE disclosure —
411
+ * only its SHA-256 digest is stored).
412
+ */
347
413
  async register(body) {
348
414
  const metadata = validateClientRegistration(body, this.validation);
349
415
  await this.guard?.({ metadata });
350
416
  if (this.unusedClientTtlMs !== void 0) await this.store.deleteUnusedBefore(this.clock.now() - this.unusedClientTtlMs);
351
417
  if (await this.store.count() >= this.maxClients) throw new ClientRegistrationError("invalid_client_metadata", "registration limit reached");
418
+ if (metadata.tokenEndpointAuthMethod === "client_secret_post") {
419
+ const clientSecret = mintClientSecret();
420
+ return {
421
+ ...await this.store.create({
422
+ ...metadata,
423
+ clientSecretHash: hashClientSecret(clientSecret)
424
+ }),
425
+ clientSecret,
426
+ clientSecretExpiresAt: 0
427
+ };
428
+ }
352
429
  return this.store.create(metadata);
353
430
  }
354
431
  };
@@ -359,13 +436,14 @@ const DEFAULT_DYNAMIC_TOKEN_POLICY = {
359
436
  ttl: 720 * 60 * 6e4
360
437
  };
361
438
  /**
362
- * Policy for RFC 7591 dynamically-registered public clients (OAUTH.md R2) on
363
- * the `ClientRedirectPolicy` seam. `resolveClient` authorizes the client +
439
+ * Policy for RFC 7591 dynamically-registered clients (OAUTH.md R2) on the
440
+ * `ClientRedirectPolicy` seam. `resolveClient` authorizes the client +
364
441
  * `redirect_uri` against ITS registered allowlist and resolves the granted
365
442
  * scope + token policy; `authenticateClient` re-checks existence at `/token`
366
- * (`token_endpoint_auth_method: "none"` ⇒ no secret — PKCE is the binding, and
367
- * a registration garbage-collected mid-flight fails closed). Dynamic clients
368
- * receive an access token only — NO `id_token` in v1 (OAUTH.md R6).
443
+ * (a registration garbage-collected mid-flight fails closed) and, for a
444
+ * `client_secret_post` registration, validates the presented secret against
445
+ * the stored digest (public `"none"` clients: PKCE is the binding). Dynamic
446
+ * clients receive an access token only — NO `id_token` in v1 (OAUTH.md R6).
369
447
  *
370
448
  * INVARIANT: the returned {@link ResolvedClient} always carries `clientId`, so
371
449
  * the minted code records it and the token endpoint's symmetric client binding
@@ -401,12 +479,16 @@ var DynamicClientPolicy = class {
401
479
  }
402
480
  /**
403
481
  * `/token`-side check: the client must still exist (fail closed when the
404
- * registration was deleted/GC'd between authorize and redemption). No secret
405
- * is checked — public client, PKCE is the binding; a spurious
406
- * `client_secret` is ignored.
482
+ * registration was deleted/GC'd between authorize and redemption). A client
483
+ * registered with `token_endpoint_auth_method: "client_secret_post"` must
484
+ * additionally present its minted `client_secret` (constant-time check
485
+ * against the stored digest). For a public (`"none"`) client no secret is
486
+ * checked — PKCE is the binding; a spurious `client_secret` is ignored.
407
487
  */
408
488
  async authenticateClient(args) {
409
- await this.requireClient(args.clientId);
489
+ const client = await this.requireClient(args.clientId);
490
+ if (client.tokenEndpointAuthMethod !== "client_secret_post") return;
491
+ if (client.clientSecretHash === void 0 || args.clientSecret === void 0 || !verifyClientSecret(args.clientSecret, client.clientSecretHash)) throw new AuthorizeError("invalid_client", "client authentication failed");
410
492
  }
411
493
  /** Known-ness probe for `CompositeClientPolicy` dispatch. */
412
494
  async hasClient(clientId) {
@@ -537,7 +619,9 @@ function canonicalizeIssuer(issuer) {
537
619
  *
538
620
  * Capability fields are fixed to what the server actually implements:
539
621
  * `response_types_supported` `["code"]`, `grant_types_supported`
540
- * `["authorization_code"]`, `code_challenge_methods_supported` `["S256"]`
622
+ * `["authorization_code", "refresh_token"]` (the grant is implemented server-
623
+ * wide; whether a given client's grant mints a refresh token is per-policy —
624
+ * `TokenPolicy.refresh`), `code_challenge_methods_supported` `["S256"]`
541
625
  * (PKCE is mandatory — it is the binding for public clients). Optional fields
542
626
  * are omitted entirely (no `undefined` keys) so the serialized JSON carries
543
627
  * only what was configured.
@@ -552,7 +636,7 @@ function buildAuthorizationServerMetadata(opts) {
552
636
  ...opts.registrationEndpoint !== void 0 && { registration_endpoint: opts.registrationEndpoint },
553
637
  ...opts.jwksUri !== void 0 && { jwks_uri: opts.jwksUri },
554
638
  response_types_supported: ["code"],
555
- grant_types_supported: ["authorization_code"],
639
+ grant_types_supported: ["authorization_code", "refresh_token"],
556
640
  code_challenge_methods_supported: ["S256"],
557
641
  token_endpoint_auth_methods_supported: authMethods.includes("none") ? authMethods : ["none", ...authMethods],
558
642
  ...opts.scopesSupported !== void 0 && { scopes_supported: opts.scopesSupported }
@@ -612,6 +696,7 @@ exports.AuthCodeStoreMemory = require_dynamic_client_store.AuthCodeStoreMemory;
612
696
  exports.AuthorizeError = AuthorizeError;
613
697
  exports.ClientRegistrationError = ClientRegistrationError;
614
698
  exports.CompositeClientPolicy = CompositeClientPolicy;
699
+ exports.DEFAULT_AUTHZ_REFRESH_TTL_MS = DEFAULT_AUTHZ_REFRESH_TTL_MS;
615
700
  exports.DEFAULT_PENDING_TTL_MS = require_dynamic_client_store.DEFAULT_PENDING_TTL_MS;
616
701
  exports.DynamicClientPolicy = DynamicClientPolicy;
617
702
  exports.DynamicClientRegistration = DynamicClientRegistration;
@@ -628,6 +713,10 @@ exports.buildAuthorizationServerMetadata = buildAuthorizationServerMetadata;
628
713
  exports.buildProtectedResourceMetadata = buildProtectedResourceMetadata;
629
714
  exports.buildWwwAuthenticateBearerChallenge = buildWwwAuthenticateBearerChallenge;
630
715
  exports.canonicalizeIssuer = canonicalizeIssuer;
716
+ exports.hashClientSecret = hashClientSecret;
631
717
  exports.isLoopbackRedirectUri = isLoopbackRedirectUri;
718
+ exports.mintClientSecret = mintClientSecret;
632
719
  exports.scopeGrants = scopeGrants;
720
+ exports.tokenPolicyToIssueOptions = tokenPolicyToIssueOptions;
633
721
  exports.validateClientRegistration = validateClientRegistration;
722
+ exports.verifyClientSecret = verifyClientSecret;
package/dist/authz.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { t as Clock } from "./clock-BjXa0LXb.cjs";
2
- import { _ as TokenPolicy, a as NewDynamicClient, c as AuthCodeStoreMemory, d as DEFAULT_PENDING_TTL_MS, f as NewPendingAuthorization, g as PendingAuthorizationStoreMemoryOptions, h as PendingAuthorizationStoreMemory, i as DynamicClientStoreMemoryOptions, l as AuthCodeStoreMemoryOptions, m as PendingAuthorizationStore, n as DynamicClientStore, o as AuthCode, p as PendingAuthorization, r as DynamicClientStoreMemory, s as AuthCodeStore, t as DynamicClient, u as NewAuthCode } from "./dynamic-client-store-DzqdUwnw.cjs";
1
+ import { t as Clock } from "./clock-DJ_eroHW.cjs";
2
+ import { _ as PendingAuthorizationStoreMemoryOptions, a as DynamicClientStoreMemoryOptions, b as tokenPolicyToIssueOptions, c as AuthCodeStore, d as NewAuthCode, f as DEFAULT_PENDING_TTL_MS, g as PendingAuthorizationStoreMemory, h as PendingAuthorizationStore, i as DynamicClientStoreMemory, l as AuthCodeStoreMemory, m as PendingAuthorization, n as DynamicClientAuthMethod, o as NewDynamicClient, p as NewPendingAuthorization, r as DynamicClientStore, s as AuthCode, t as DynamicClient, u as AuthCodeStoreMemoryOptions, v as DEFAULT_AUTHZ_REFRESH_TTL_MS, y as TokenPolicy } from "./dynamic-client-store-DbiSLOj0.cjs";
3
3
  import { JWK } from "jose";
4
4
 
5
5
  //#region src/authz/authz-errors.d.ts
@@ -269,6 +269,15 @@ interface ClientRegistrationValidationOptions {
269
269
  * `DynamicClientPolicyOptions.allowedScopes` (the server allow-list).
270
270
  */
271
271
  allowedScopes?: string[];
272
+ /**
273
+ * Which `token_endpoint_auth_method` values registrations may use. Default:
274
+ * both supported methods (`["none", "client_secret_post"]` — matching what
275
+ * the RFC 8414 document advertises). Narrow to `["none"]` for a
276
+ * public-clients-only deployment. An explicit ask outside this list is
277
+ * REJECTED, never silently downgraded — a client that asked for a secret
278
+ * must not end up public without noticing.
279
+ */
280
+ allowedTokenEndpointAuthMethods?: DynamicClientAuthMethod[];
272
281
  }
273
282
  /**
274
283
  * Validate + normalize an RFC 7591 registration request body into a
@@ -277,13 +286,14 @@ interface ClientRegistrationValidationOptions {
277
286
  * Normalization is allowed by RFC 7591 §2 (the server MAY replace requested
278
287
  * metadata with its own values) and is load-bearing for real connectors:
279
288
  * `grant_types` / `response_types` are INTERSECTED with what the server
280
- * supports (a connector requesting `["authorization_code", "refresh_token"]`
281
- * registers with `["authorization_code"]` — the 201 echo of the narrowed set
282
- * is the contract) rather than rejected. `token_endpoint_auth_method` defaults
283
- * to `"none"` when absent (v1 is public-clients-only, so the RFC's
284
- * `client_secret_basic` default is unsupported), but an EXPLICIT non-`"none"`
285
- * ask is rejected — never silently downgrade a client that asked for a secret.
286
- * Unknown fields are ignored and never echoed.
289
+ * supports (an unsupported grant is dropped from the echo — the 201 echo of
290
+ * the narrowed set is the contract) rather than rejected, but the result must
291
+ * still include `authorization_code` (it is the only way to establish a grant;
292
+ * `refresh_token` alone mints nothing). `token_endpoint_auth_method` defaults
293
+ * to `"none"` when absent (the RFC's `client_secret_basic` default is
294
+ * unsupported — secrets travel in the POST form body); an EXPLICIT ask outside
295
+ * the allowed set is rejected — never silently downgrade a client that asked
296
+ * for a secret. Unknown fields are ignored and never echoed.
287
297
  */
288
298
  declare function validateClientRegistration(body: unknown, opts?: ClientRegistrationValidationOptions): NewDynamicClient;
289
299
  interface DynamicClientRegistrationOptions {
@@ -313,12 +323,28 @@ interface DynamicClientRegistrationOptions {
313
323
  /** Injectable clock for deterministic GC tests. Defaults to {@link defaultClock}. */
314
324
  clock?: Clock;
315
325
  }
326
+ /**
327
+ * What {@link DynamicClientRegistration.register} returns: the persisted
328
+ * record plus — for a `client_secret_post` registration — the plaintext
329
+ * `clientSecret`, surfaced HERE and ONLY here (RFC 7591 §3.2.1: the secret is
330
+ * disclosed once in the registration response; the store keeps only its hash).
331
+ */
332
+ type RegisteredDynamicClient = DynamicClient & {
333
+ clientSecret?: string;
334
+ /**
335
+ * Expiry of the minted secret in seconds since epoch (RFC 7591 §3.2.1's
336
+ * unit); `0` ⇒ the secret never expires. Present iff {@link clientSecret}
337
+ * is — decided HERE, where the secret is minted, so HTTP adapters echo the
338
+ * lifecycle instead of asserting their own.
339
+ */
340
+ clientSecretExpiresAt?: number;
341
+ };
316
342
  /**
317
343
  * The RFC 7591 registration operation behind `POST {issuer}/register`
318
344
  * (OAUTH.md R2): validate → guard → lazy GC of never-used rows → hard cap →
319
- * persist. Framework-free — `@aooth/auth-moost`'s controller endpoint is a
320
- * thin HTTP adapter over `register()`, and non-moost servers can call it
321
- * directly.
345
+ * mint secret (confidential) → persist. Framework-free — `@aooth/auth-moost`'s
346
+ * controller endpoint is a thin HTTP adapter over `register()`, and non-moost
347
+ * servers can call it directly.
322
348
  */
323
349
  declare class DynamicClientRegistration {
324
350
  private readonly store;
@@ -328,10 +354,33 @@ declare class DynamicClientRegistration {
328
354
  private readonly validation?;
329
355
  private readonly clock;
330
356
  constructor(opts: DynamicClientRegistrationOptions);
331
- /** Validate and persist a registration request body; returns the minted client. */
332
- register(body: unknown): Promise<DynamicClient>;
357
+ /**
358
+ * Validate and persist a registration request body; returns the minted
359
+ * client. For a `client_secret_post` registration the returned record
360
+ * additionally carries the plaintext `clientSecret` (the ONE disclosure —
361
+ * only its SHA-256 digest is stored).
362
+ */
363
+ register(body: unknown): Promise<RegisteredDynamicClient>;
333
364
  }
334
365
  //#endregion
366
+ //#region src/authz/client-secret.d.ts
367
+ /**
368
+ * Mint a confidential dynamic client's secret (RFC 7591 `client_secret`) — a
369
+ * plain {@link generateOpaqueToken} mint. Returned to the registrant ONCE in
370
+ * the registration response; only its {@link hashClientSecret} digest is
371
+ * stored.
372
+ */
373
+ declare function mintClientSecret(): string;
374
+ /**
375
+ * Storage digest for a client secret — plain SHA-256 (hex). No KDF/salt on
376
+ * purpose: the secret is high-entropy server-minted material (never a human
377
+ * password), so brute-forcing the digest is infeasible and a per-row salt
378
+ * buys nothing.
379
+ */
380
+ declare function hashClientSecret(secret: string): string;
381
+ /** Constant-time check of a presented secret against a stored digest. */
382
+ declare function verifyClientSecret(secret: string, hash: string): boolean;
383
+ //#endregion
335
384
  //#region src/authz/dynamic-client-policy.d.ts
336
385
  interface DynamicClientPolicyOptions {
337
386
  store: DynamicClientStore;
@@ -353,13 +402,14 @@ interface DynamicClientPolicyOptions {
353
402
  clock?: Clock;
354
403
  }
355
404
  /**
356
- * Policy for RFC 7591 dynamically-registered public clients (OAUTH.md R2) on
357
- * the `ClientRedirectPolicy` seam. `resolveClient` authorizes the client +
405
+ * Policy for RFC 7591 dynamically-registered clients (OAUTH.md R2) on the
406
+ * `ClientRedirectPolicy` seam. `resolveClient` authorizes the client +
358
407
  * `redirect_uri` against ITS registered allowlist and resolves the granted
359
408
  * scope + token policy; `authenticateClient` re-checks existence at `/token`
360
- * (`token_endpoint_auth_method: "none"` ⇒ no secret — PKCE is the binding, and
361
- * a registration garbage-collected mid-flight fails closed). Dynamic clients
362
- * receive an access token only — NO `id_token` in v1 (OAUTH.md R6).
409
+ * (a registration garbage-collected mid-flight fails closed) and, for a
410
+ * `client_secret_post` registration, validates the presented secret against
411
+ * the stored digest (public `"none"` clients: PKCE is the binding). Dynamic
412
+ * clients receive an access token only — NO `id_token` in v1 (OAUTH.md R6).
363
413
  *
364
414
  * INVARIANT: the returned {@link ResolvedClient} always carries `clientId`, so
365
415
  * the minted code records it and the token endpoint's symmetric client binding
@@ -379,9 +429,11 @@ declare class DynamicClientPolicy implements ClientRedirectPolicy {
379
429
  }): Promise<ResolvedClient>;
380
430
  /**
381
431
  * `/token`-side check: the client must still exist (fail closed when the
382
- * registration was deleted/GC'd between authorize and redemption). No secret
383
- * is checked — public client, PKCE is the binding; a spurious
384
- * `client_secret` is ignored.
432
+ * registration was deleted/GC'd between authorize and redemption). A client
433
+ * registered with `token_endpoint_auth_method: "client_secret_post"` must
434
+ * additionally present its minted `client_secret` (constant-time check
435
+ * against the stored digest). For a public (`"none"`) client no secret is
436
+ * checked — PKCE is the binding; a spurious `client_secret` is ignored.
385
437
  */
386
438
  authenticateClient(args: {
387
439
  clientId?: string;
@@ -558,7 +610,9 @@ interface BuildAuthorizationServerMetadataOptions {
558
610
  *
559
611
  * Capability fields are fixed to what the server actually implements:
560
612
  * `response_types_supported` `["code"]`, `grant_types_supported`
561
- * `["authorization_code"]`, `code_challenge_methods_supported` `["S256"]`
613
+ * `["authorization_code", "refresh_token"]` (the grant is implemented server-
614
+ * wide; whether a given client's grant mints a refresh token is per-policy —
615
+ * `TokenPolicy.refresh`), `code_challenge_methods_supported` `["S256"]`
562
616
  * (PKCE is mandatory — it is the binding for public clients). Optional fields
563
617
  * are omitted entirely (no `undefined` keys) so the serialized JSON carries
564
618
  * only what was configured.
@@ -627,4 +681,4 @@ interface WwwAuthenticateBearerChallengeOptions {
627
681
  */
628
682
  declare function buildWwwAuthenticateBearerChallenge(opts?: WwwAuthenticateBearerChallengeOptions): string;
629
683
  //#endregion
630
- export { type AuthCode, AuthCodeStore, AuthCodeStoreMemory, type AuthCodeStoreMemoryOptions, type AuthorizationServerMetadata, AuthorizeError, type AuthorizeErrorCode, type BuildAuthorizationServerMetadataOptions, type BuildProtectedResourceMetadataOptions, type ClientRedirectPolicy, ClientRegistrationError, type ClientRegistrationErrorCode, type ClientRegistrationValidationOptions, CompositeClientPolicy, type CompositeClientPolicyOptions, DEFAULT_PENDING_TTL_MS, type DynamicClient, DynamicClientPolicy, type DynamicClientPolicyOptions, DynamicClientRegistration, type DynamicClientRegistrationOptions, DynamicClientStore, DynamicClientStoreMemory, type DynamicClientStoreMemoryOptions, type IdTokenAlg, type IdTokenClaims, IdTokenSigner, type IdTokenSignerOptions, LoopbackClientPolicy, type LoopbackClientPolicyOptions, type NewAuthCode, type NewDynamicClient, type NewPendingAuthorization, NoopOidcClaimsResolver, OidcClaimsResolver, type PendingAuthorization, PendingAuthorizationStore, PendingAuthorizationStoreMemory, type PendingAuthorizationStoreMemoryOptions, type ProtectedResourceMetadata, type RegisteredClient, RegisteredClientPolicy, type RegisteredClientPolicyOptions, type ResolvedClient, type TokenPolicy, type WwwAuthenticateBearerChallengeOptions, buildAuthorizationServerMetadata, buildProtectedResourceMetadata, buildWwwAuthenticateBearerChallenge, canonicalizeIssuer, isLoopbackRedirectUri, scopeGrants, validateClientRegistration };
684
+ export { type AuthCode, AuthCodeStore, AuthCodeStoreMemory, type AuthCodeStoreMemoryOptions, type AuthorizationServerMetadata, AuthorizeError, type AuthorizeErrorCode, type BuildAuthorizationServerMetadataOptions, type BuildProtectedResourceMetadataOptions, type ClientRedirectPolicy, ClientRegistrationError, type ClientRegistrationErrorCode, type ClientRegistrationValidationOptions, CompositeClientPolicy, type CompositeClientPolicyOptions, DEFAULT_AUTHZ_REFRESH_TTL_MS, DEFAULT_PENDING_TTL_MS, type DynamicClient, type DynamicClientAuthMethod, DynamicClientPolicy, type DynamicClientPolicyOptions, DynamicClientRegistration, type DynamicClientRegistrationOptions, DynamicClientStore, DynamicClientStoreMemory, type DynamicClientStoreMemoryOptions, type IdTokenAlg, type IdTokenClaims, IdTokenSigner, type IdTokenSignerOptions, LoopbackClientPolicy, type LoopbackClientPolicyOptions, type NewAuthCode, type NewDynamicClient, type NewPendingAuthorization, NoopOidcClaimsResolver, OidcClaimsResolver, type PendingAuthorization, PendingAuthorizationStore, PendingAuthorizationStoreMemory, type PendingAuthorizationStoreMemoryOptions, type ProtectedResourceMetadata, type RegisteredClient, RegisteredClientPolicy, type RegisteredClientPolicyOptions, type RegisteredDynamicClient, type ResolvedClient, type TokenPolicy, type WwwAuthenticateBearerChallengeOptions, buildAuthorizationServerMetadata, buildProtectedResourceMetadata, buildWwwAuthenticateBearerChallenge, canonicalizeIssuer, hashClientSecret, isLoopbackRedirectUri, mintClientSecret, scopeGrants, tokenPolicyToIssueOptions, validateClientRegistration, verifyClientSecret };
package/dist/authz.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { t as Clock } from "./clock-BjXa0LXb.mjs";
2
- import { _ as TokenPolicy, a as NewDynamicClient, c as AuthCodeStoreMemory, d as DEFAULT_PENDING_TTL_MS, f as NewPendingAuthorization, g as PendingAuthorizationStoreMemoryOptions, h as PendingAuthorizationStoreMemory, i as DynamicClientStoreMemoryOptions, l as AuthCodeStoreMemoryOptions, m as PendingAuthorizationStore, n as DynamicClientStore, o as AuthCode, p as PendingAuthorization, r as DynamicClientStoreMemory, s as AuthCodeStore, t as DynamicClient, u as NewAuthCode } from "./dynamic-client-store-oHEsQaJg.mjs";
1
+ import { t as Clock } from "./clock-DJ_eroHW.mjs";
2
+ import { _ as PendingAuthorizationStoreMemoryOptions, a as DynamicClientStoreMemoryOptions, b as tokenPolicyToIssueOptions, c as AuthCodeStore, d as NewAuthCode, f as DEFAULT_PENDING_TTL_MS, g as PendingAuthorizationStoreMemory, h as PendingAuthorizationStore, i as DynamicClientStoreMemory, l as AuthCodeStoreMemory, m as PendingAuthorization, n as DynamicClientAuthMethod, o as NewDynamicClient, p as NewPendingAuthorization, r as DynamicClientStore, s as AuthCode, t as DynamicClient, u as AuthCodeStoreMemoryOptions, v as DEFAULT_AUTHZ_REFRESH_TTL_MS, y as TokenPolicy } from "./dynamic-client-store-DJgtMjPw.mjs";
3
3
  import { JWK } from "jose";
4
4
 
5
5
  //#region src/authz/authz-errors.d.ts
@@ -269,6 +269,15 @@ interface ClientRegistrationValidationOptions {
269
269
  * `DynamicClientPolicyOptions.allowedScopes` (the server allow-list).
270
270
  */
271
271
  allowedScopes?: string[];
272
+ /**
273
+ * Which `token_endpoint_auth_method` values registrations may use. Default:
274
+ * both supported methods (`["none", "client_secret_post"]` — matching what
275
+ * the RFC 8414 document advertises). Narrow to `["none"]` for a
276
+ * public-clients-only deployment. An explicit ask outside this list is
277
+ * REJECTED, never silently downgraded — a client that asked for a secret
278
+ * must not end up public without noticing.
279
+ */
280
+ allowedTokenEndpointAuthMethods?: DynamicClientAuthMethod[];
272
281
  }
273
282
  /**
274
283
  * Validate + normalize an RFC 7591 registration request body into a
@@ -277,13 +286,14 @@ interface ClientRegistrationValidationOptions {
277
286
  * Normalization is allowed by RFC 7591 §2 (the server MAY replace requested
278
287
  * metadata with its own values) and is load-bearing for real connectors:
279
288
  * `grant_types` / `response_types` are INTERSECTED with what the server
280
- * supports (a connector requesting `["authorization_code", "refresh_token"]`
281
- * registers with `["authorization_code"]` — the 201 echo of the narrowed set
282
- * is the contract) rather than rejected. `token_endpoint_auth_method` defaults
283
- * to `"none"` when absent (v1 is public-clients-only, so the RFC's
284
- * `client_secret_basic` default is unsupported), but an EXPLICIT non-`"none"`
285
- * ask is rejected — never silently downgrade a client that asked for a secret.
286
- * Unknown fields are ignored and never echoed.
289
+ * supports (an unsupported grant is dropped from the echo — the 201 echo of
290
+ * the narrowed set is the contract) rather than rejected, but the result must
291
+ * still include `authorization_code` (it is the only way to establish a grant;
292
+ * `refresh_token` alone mints nothing). `token_endpoint_auth_method` defaults
293
+ * to `"none"` when absent (the RFC's `client_secret_basic` default is
294
+ * unsupported — secrets travel in the POST form body); an EXPLICIT ask outside
295
+ * the allowed set is rejected — never silently downgrade a client that asked
296
+ * for a secret. Unknown fields are ignored and never echoed.
287
297
  */
288
298
  declare function validateClientRegistration(body: unknown, opts?: ClientRegistrationValidationOptions): NewDynamicClient;
289
299
  interface DynamicClientRegistrationOptions {
@@ -313,12 +323,28 @@ interface DynamicClientRegistrationOptions {
313
323
  /** Injectable clock for deterministic GC tests. Defaults to {@link defaultClock}. */
314
324
  clock?: Clock;
315
325
  }
326
+ /**
327
+ * What {@link DynamicClientRegistration.register} returns: the persisted
328
+ * record plus — for a `client_secret_post` registration — the plaintext
329
+ * `clientSecret`, surfaced HERE and ONLY here (RFC 7591 §3.2.1: the secret is
330
+ * disclosed once in the registration response; the store keeps only its hash).
331
+ */
332
+ type RegisteredDynamicClient = DynamicClient & {
333
+ clientSecret?: string;
334
+ /**
335
+ * Expiry of the minted secret in seconds since epoch (RFC 7591 §3.2.1's
336
+ * unit); `0` ⇒ the secret never expires. Present iff {@link clientSecret}
337
+ * is — decided HERE, where the secret is minted, so HTTP adapters echo the
338
+ * lifecycle instead of asserting their own.
339
+ */
340
+ clientSecretExpiresAt?: number;
341
+ };
316
342
  /**
317
343
  * The RFC 7591 registration operation behind `POST {issuer}/register`
318
344
  * (OAUTH.md R2): validate → guard → lazy GC of never-used rows → hard cap →
319
- * persist. Framework-free — `@aooth/auth-moost`'s controller endpoint is a
320
- * thin HTTP adapter over `register()`, and non-moost servers can call it
321
- * directly.
345
+ * mint secret (confidential) → persist. Framework-free — `@aooth/auth-moost`'s
346
+ * controller endpoint is a thin HTTP adapter over `register()`, and non-moost
347
+ * servers can call it directly.
322
348
  */
323
349
  declare class DynamicClientRegistration {
324
350
  private readonly store;
@@ -328,10 +354,33 @@ declare class DynamicClientRegistration {
328
354
  private readonly validation?;
329
355
  private readonly clock;
330
356
  constructor(opts: DynamicClientRegistrationOptions);
331
- /** Validate and persist a registration request body; returns the minted client. */
332
- register(body: unknown): Promise<DynamicClient>;
357
+ /**
358
+ * Validate and persist a registration request body; returns the minted
359
+ * client. For a `client_secret_post` registration the returned record
360
+ * additionally carries the plaintext `clientSecret` (the ONE disclosure —
361
+ * only its SHA-256 digest is stored).
362
+ */
363
+ register(body: unknown): Promise<RegisteredDynamicClient>;
333
364
  }
334
365
  //#endregion
366
+ //#region src/authz/client-secret.d.ts
367
+ /**
368
+ * Mint a confidential dynamic client's secret (RFC 7591 `client_secret`) — a
369
+ * plain {@link generateOpaqueToken} mint. Returned to the registrant ONCE in
370
+ * the registration response; only its {@link hashClientSecret} digest is
371
+ * stored.
372
+ */
373
+ declare function mintClientSecret(): string;
374
+ /**
375
+ * Storage digest for a client secret — plain SHA-256 (hex). No KDF/salt on
376
+ * purpose: the secret is high-entropy server-minted material (never a human
377
+ * password), so brute-forcing the digest is infeasible and a per-row salt
378
+ * buys nothing.
379
+ */
380
+ declare function hashClientSecret(secret: string): string;
381
+ /** Constant-time check of a presented secret against a stored digest. */
382
+ declare function verifyClientSecret(secret: string, hash: string): boolean;
383
+ //#endregion
335
384
  //#region src/authz/dynamic-client-policy.d.ts
336
385
  interface DynamicClientPolicyOptions {
337
386
  store: DynamicClientStore;
@@ -353,13 +402,14 @@ interface DynamicClientPolicyOptions {
353
402
  clock?: Clock;
354
403
  }
355
404
  /**
356
- * Policy for RFC 7591 dynamically-registered public clients (OAUTH.md R2) on
357
- * the `ClientRedirectPolicy` seam. `resolveClient` authorizes the client +
405
+ * Policy for RFC 7591 dynamically-registered clients (OAUTH.md R2) on the
406
+ * `ClientRedirectPolicy` seam. `resolveClient` authorizes the client +
358
407
  * `redirect_uri` against ITS registered allowlist and resolves the granted
359
408
  * scope + token policy; `authenticateClient` re-checks existence at `/token`
360
- * (`token_endpoint_auth_method: "none"` ⇒ no secret — PKCE is the binding, and
361
- * a registration garbage-collected mid-flight fails closed). Dynamic clients
362
- * receive an access token only — NO `id_token` in v1 (OAUTH.md R6).
409
+ * (a registration garbage-collected mid-flight fails closed) and, for a
410
+ * `client_secret_post` registration, validates the presented secret against
411
+ * the stored digest (public `"none"` clients: PKCE is the binding). Dynamic
412
+ * clients receive an access token only — NO `id_token` in v1 (OAUTH.md R6).
363
413
  *
364
414
  * INVARIANT: the returned {@link ResolvedClient} always carries `clientId`, so
365
415
  * the minted code records it and the token endpoint's symmetric client binding
@@ -379,9 +429,11 @@ declare class DynamicClientPolicy implements ClientRedirectPolicy {
379
429
  }): Promise<ResolvedClient>;
380
430
  /**
381
431
  * `/token`-side check: the client must still exist (fail closed when the
382
- * registration was deleted/GC'd between authorize and redemption). No secret
383
- * is checked — public client, PKCE is the binding; a spurious
384
- * `client_secret` is ignored.
432
+ * registration was deleted/GC'd between authorize and redemption). A client
433
+ * registered with `token_endpoint_auth_method: "client_secret_post"` must
434
+ * additionally present its minted `client_secret` (constant-time check
435
+ * against the stored digest). For a public (`"none"`) client no secret is
436
+ * checked — PKCE is the binding; a spurious `client_secret` is ignored.
385
437
  */
386
438
  authenticateClient(args: {
387
439
  clientId?: string;
@@ -558,7 +610,9 @@ interface BuildAuthorizationServerMetadataOptions {
558
610
  *
559
611
  * Capability fields are fixed to what the server actually implements:
560
612
  * `response_types_supported` `["code"]`, `grant_types_supported`
561
- * `["authorization_code"]`, `code_challenge_methods_supported` `["S256"]`
613
+ * `["authorization_code", "refresh_token"]` (the grant is implemented server-
614
+ * wide; whether a given client's grant mints a refresh token is per-policy —
615
+ * `TokenPolicy.refresh`), `code_challenge_methods_supported` `["S256"]`
562
616
  * (PKCE is mandatory — it is the binding for public clients). Optional fields
563
617
  * are omitted entirely (no `undefined` keys) so the serialized JSON carries
564
618
  * only what was configured.
@@ -627,4 +681,4 @@ interface WwwAuthenticateBearerChallengeOptions {
627
681
  */
628
682
  declare function buildWwwAuthenticateBearerChallenge(opts?: WwwAuthenticateBearerChallengeOptions): string;
629
683
  //#endregion
630
- export { type AuthCode, AuthCodeStore, AuthCodeStoreMemory, type AuthCodeStoreMemoryOptions, type AuthorizationServerMetadata, AuthorizeError, type AuthorizeErrorCode, type BuildAuthorizationServerMetadataOptions, type BuildProtectedResourceMetadataOptions, type ClientRedirectPolicy, ClientRegistrationError, type ClientRegistrationErrorCode, type ClientRegistrationValidationOptions, CompositeClientPolicy, type CompositeClientPolicyOptions, DEFAULT_PENDING_TTL_MS, type DynamicClient, DynamicClientPolicy, type DynamicClientPolicyOptions, DynamicClientRegistration, type DynamicClientRegistrationOptions, DynamicClientStore, DynamicClientStoreMemory, type DynamicClientStoreMemoryOptions, type IdTokenAlg, type IdTokenClaims, IdTokenSigner, type IdTokenSignerOptions, LoopbackClientPolicy, type LoopbackClientPolicyOptions, type NewAuthCode, type NewDynamicClient, type NewPendingAuthorization, NoopOidcClaimsResolver, OidcClaimsResolver, type PendingAuthorization, PendingAuthorizationStore, PendingAuthorizationStoreMemory, type PendingAuthorizationStoreMemoryOptions, type ProtectedResourceMetadata, type RegisteredClient, RegisteredClientPolicy, type RegisteredClientPolicyOptions, type ResolvedClient, type TokenPolicy, type WwwAuthenticateBearerChallengeOptions, buildAuthorizationServerMetadata, buildProtectedResourceMetadata, buildWwwAuthenticateBearerChallenge, canonicalizeIssuer, isLoopbackRedirectUri, scopeGrants, validateClientRegistration };
684
+ export { type AuthCode, AuthCodeStore, AuthCodeStoreMemory, type AuthCodeStoreMemoryOptions, type AuthorizationServerMetadata, AuthorizeError, type AuthorizeErrorCode, type BuildAuthorizationServerMetadataOptions, type BuildProtectedResourceMetadataOptions, type ClientRedirectPolicy, ClientRegistrationError, type ClientRegistrationErrorCode, type ClientRegistrationValidationOptions, CompositeClientPolicy, type CompositeClientPolicyOptions, DEFAULT_AUTHZ_REFRESH_TTL_MS, DEFAULT_PENDING_TTL_MS, type DynamicClient, type DynamicClientAuthMethod, DynamicClientPolicy, type DynamicClientPolicyOptions, DynamicClientRegistration, type DynamicClientRegistrationOptions, DynamicClientStore, DynamicClientStoreMemory, type DynamicClientStoreMemoryOptions, type IdTokenAlg, type IdTokenClaims, IdTokenSigner, type IdTokenSignerOptions, LoopbackClientPolicy, type LoopbackClientPolicyOptions, type NewAuthCode, type NewDynamicClient, type NewPendingAuthorization, NoopOidcClaimsResolver, OidcClaimsResolver, type PendingAuthorization, PendingAuthorizationStore, PendingAuthorizationStoreMemory, type PendingAuthorizationStoreMemoryOptions, type ProtectedResourceMetadata, type RegisteredClient, RegisteredClientPolicy, type RegisteredClientPolicyOptions, type RegisteredDynamicClient, type ResolvedClient, type TokenPolicy, type WwwAuthenticateBearerChallengeOptions, buildAuthorizationServerMetadata, buildProtectedResourceMetadata, buildWwwAuthenticateBearerChallenge, canonicalizeIssuer, hashClientSecret, isLoopbackRedirectUri, mintClientSecret, scopeGrants, tokenPolicyToIssueOptions, validateClientRegistration, verifyClientSecret };