@aooth/auth 0.1.46 → 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.
- package/dist/atscript-db.cjs +3 -1
- package/dist/atscript-db.d.cts +4 -3
- package/dist/atscript-db.d.mts +4 -3
- package/dist/atscript-db.mjs +3 -1
- package/dist/auth-credential-C3qebKuy.d.mts +245 -0
- package/dist/auth-credential-CEijxoGU.d.cts +245 -0
- package/dist/authz.cjs +124 -35
- package/dist/authz.d.cts +78 -24
- package/dist/authz.d.mts +78 -24
- package/dist/authz.mjs +121 -37
- package/dist/{store-BG6m6oSJ.d.mts → clock-DJ_eroHW.d.cts} +50 -1
- package/dist/{store-BG6m6oSJ.d.cts → clock-DJ_eroHW.d.mts} +50 -1
- package/dist/{dynamic-client-store-DLRfntHr.mjs → dynamic-client-store-B1JwFHdP.mjs} +1 -0
- package/dist/{dynamic-client-store-DzqdUwnw.d.cts → dynamic-client-store-DJgtMjPw.d.mts} +58 -9
- package/dist/{dynamic-client-store-oHEsQaJg.d.mts → dynamic-client-store-DbiSLOj0.d.cts} +58 -9
- package/dist/{dynamic-client-store-DAStgv2j.cjs → dynamic-client-store-DykM9QOT.cjs} +1 -0
- package/dist/index.cjs +39 -26
- package/dist/index.d.cts +12 -218
- package/dist/index.d.mts +12 -218
- package/dist/index.mjs +39 -27
- package/dist/opaque-token-BaMOrC1A.mjs +13 -0
- package/dist/opaque-token-CaZgD2i6.cjs +18 -0
- package/dist/redis.d.cts +2 -2
- package/dist/redis.d.mts +2 -2
- package/dist/{store-N9daSmHS.d.cts → store-BYnpA7VK.d.cts} +1 -1
- package/dist/{store-jFgby4bK.d.mts → store-pKh0ZaGG.d.mts} +1 -1
- package/package.json +8 -8
- package/src/atscript-db/auth-credential.as +16 -0
- package/src/atscript-db/auth-credential.as.d.ts +4 -1
- package/src/atscript-db/dynamic-client.as +11 -1
- package/src/atscript-db/dynamic-client.as.d.ts +3 -0
- package/dist/clock-BjXa0LXb.d.cts +0 -14
- 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
|
|
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
|
|
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 (
|
|
278
|
-
*
|
|
279
|
-
* is the
|
|
280
|
-
*
|
|
281
|
-
* `
|
|
282
|
-
*
|
|
283
|
-
*
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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
|
|
328
|
-
* thin HTTP adapter over `register()`, and non-moost
|
|
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
|
-
/**
|
|
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
|
|
363
|
-
*
|
|
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
|
-
* (
|
|
367
|
-
*
|
|
368
|
-
*
|
|
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).
|
|
405
|
-
*
|
|
406
|
-
* `client_secret`
|
|
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"
|
|
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-
|
|
2
|
-
import { _ as
|
|
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 (
|
|
281
|
-
*
|
|
282
|
-
* is the
|
|
283
|
-
*
|
|
284
|
-
* `
|
|
285
|
-
*
|
|
286
|
-
*
|
|
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
|
|
320
|
-
* thin HTTP adapter over `register()`, and non-moost
|
|
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
|
-
/**
|
|
332
|
-
|
|
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
|
|
357
|
-
*
|
|
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
|
-
* (
|
|
361
|
-
*
|
|
362
|
-
*
|
|
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).
|
|
383
|
-
*
|
|
384
|
-
* `client_secret`
|
|
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"
|
|
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-
|
|
2
|
-
import { _ as
|
|
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 (
|
|
281
|
-
*
|
|
282
|
-
* is the
|
|
283
|
-
*
|
|
284
|
-
* `
|
|
285
|
-
*
|
|
286
|
-
*
|
|
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
|
|
320
|
-
* thin HTTP adapter over `register()`, and non-moost
|
|
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
|
-
/**
|
|
332
|
-
|
|
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
|
|
357
|
-
*
|
|
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
|
-
* (
|
|
361
|
-
*
|
|
362
|
-
*
|
|
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).
|
|
383
|
-
*
|
|
384
|
-
* `client_secret`
|
|
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"
|
|
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 };
|