@cloudflare/workers-oauth-provider 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -484
- package/dist/oauth-provider.d.ts +296 -179
- package/dist/oauth-provider.js +748 -501
- package/docs/advanced-configuration.md +14 -7
- package/docs/authorization-server.md +232 -0
- package/docs/consent-page.md +14 -19
- package/docs/mcp-discovery.md +78 -0
- package/docs/migration-1.0.md +248 -43
- package/docs/resource-servers.md +27 -4
- package/docs/upstream-sign-in.md +2 -7
- package/package.json +3 -1
- package/skills/migrate-to-1.0/SKILL.md +38 -24
package/dist/oauth-provider.d.ts
CHANGED
|
@@ -1,5 +1,126 @@
|
|
|
1
1
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
2
2
|
|
|
3
|
+
//#region src/oauth-error.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The error your code throws to the library: from a `tokenExchangeCallback`, or from an
|
|
7
|
+
* `OAuthResourceServer`'s `validateToken`, to answer with a standard OAuth error response instead
|
|
8
|
+
* of a generic failure. Its own module so both hosts can use it without importing the package entry.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The internal reason behind an error response, forwarded to the `onError` hook and never
|
|
12
|
+
* placed on the wire. `category` is a stable kebab-case subsystem (`client-authentication`,
|
|
13
|
+
* `authorization-code-grant`, `refresh-token-grant`, `token-exchange-grant`,
|
|
14
|
+
* `token-endpoint-request`, `token-revocation`, `token-issuance`, `resource-indicator`,
|
|
15
|
+
* `client-registration`, `client-id-metadata-document`, `protected-resource`,
|
|
16
|
+
* `enterprise-managed-authorization`, `token-exchange-callback`); `reason` is a stable
|
|
17
|
+
* snake_case slug naming the exact check that failed. Treat both like enum members in semver.
|
|
18
|
+
* `detail` may carry structured context such as a caught error; it is never a secret.
|
|
19
|
+
*/
|
|
20
|
+
interface OAuthErrorInternal {
|
|
21
|
+
/** Stable kebab-case subsystem that produced the error. */
|
|
22
|
+
category: string;
|
|
23
|
+
/** Stable snake_case slug naming the failed check, often more specific than the wire description. */
|
|
24
|
+
reason: string;
|
|
25
|
+
/** Optional structured context, e.g. the caught error or the offending parameter. */
|
|
26
|
+
detail?: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options accepted by the {@link OAuthError} constructor.
|
|
30
|
+
*/
|
|
31
|
+
interface OAuthErrorOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Human-readable text returned in the `error_description` field.
|
|
34
|
+
*/
|
|
35
|
+
description: string;
|
|
36
|
+
/**
|
|
37
|
+
* HTTP status code for the error response. Defaults to `400`.
|
|
38
|
+
*/
|
|
39
|
+
statusCode?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Additional response headers.
|
|
42
|
+
*
|
|
43
|
+
* For transient failures (e.g. upstream rate limits), set
|
|
44
|
+
* `Retry-After` here so well-behaved clients back off instead of
|
|
45
|
+
* retry-storming. Per RFC 7231 §7.1.3 the value may be either a
|
|
46
|
+
* number of seconds or an HTTP-date.
|
|
47
|
+
*/
|
|
48
|
+
headers?: Record<string, string>;
|
|
49
|
+
/**
|
|
50
|
+
* Internal reason forwarded to the `onError` hook and never sent on the wire. The library
|
|
51
|
+
* sets it on every error it originates; a `tokenExchangeCallback` may set its own. An
|
|
52
|
+
* `OAuthError` thrown without one reaches `onError` as
|
|
53
|
+
* `{ category: 'token-exchange-callback', reason: 'callback_error', detail: error }`.
|
|
54
|
+
*/
|
|
55
|
+
internal?: OAuthErrorInternal;
|
|
56
|
+
/**
|
|
57
|
+
* For `insufficient_scope` from an `OAuthResourceServer`'s `validateToken`: every scope the
|
|
58
|
+
* operation needs, named in the `403` challenge. Defaults to the resource's `requiredScopes`.
|
|
59
|
+
*/
|
|
60
|
+
requiredScopes?: string[];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The OAuth error your code throws to the library, to answer with a standard OAuth error instead
|
|
64
|
+
* of a generic failure. It is honoured in two places:
|
|
65
|
+
*
|
|
66
|
+
* - **`tokenExchangeCallback`** (token endpoint): the response is `{ error, error_description }`
|
|
67
|
+
* with `statusCode` (default `400`) and `headers`. `invalid_grant` also revokes the grant.
|
|
68
|
+
* Anything else thrown is a `500`.
|
|
69
|
+
* - **`OAuthResourceServer`'s `validateToken`**: `invalid_token` is a `401` and
|
|
70
|
+
* `insufficient_scope` a `403`, each with a Bearer challenge (the latter naming
|
|
71
|
+
* `requiredScopes`); any other code keeps `statusCode` and `headers`, such as `429` with
|
|
72
|
+
* `Retry-After`. Anything else thrown is a `503`.
|
|
73
|
+
*
|
|
74
|
+
* Unexpected failures stay visible that way: the library doesn't catch everything and return 400.
|
|
75
|
+
* (`OAuthProvider`'s `resolveExternalToken` uses `ExternalTokenError` instead.)
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { OAuthError } from '@cloudflare/workers-oauth-provider';
|
|
80
|
+
*
|
|
81
|
+
* tokenExchangeCallback: async (options) => {
|
|
82
|
+
* if (options.grantType === 'refresh_token') {
|
|
83
|
+
* // refreshUpstream() may throw OAuthError from any depth
|
|
84
|
+
* return { newProps: await refreshUpstream(options.props) };
|
|
85
|
+
* }
|
|
86
|
+
* }
|
|
87
|
+
*
|
|
88
|
+
* async function refreshUpstream(props) {
|
|
89
|
+
* const res = await fetch(...);
|
|
90
|
+
* if (res.status === 401) {
|
|
91
|
+
* // invalid_grant can never recover: the provider also revokes this grant and its tokens.
|
|
92
|
+
* throw new OAuthError('invalid_grant', { description: 'upstream refresh token is invalid' });
|
|
93
|
+
* }
|
|
94
|
+
* if (res.status === 429) {
|
|
95
|
+
* // Mirror upstream's Retry-After if present, otherwise pick a default.
|
|
96
|
+
* throw new OAuthError('temporarily_unavailable', {
|
|
97
|
+
* description: 'upstream rate limited',
|
|
98
|
+
* statusCode: 429,
|
|
99
|
+
* headers: { 'Retry-After': res.headers.get('retry-after') ?? '60' },
|
|
100
|
+
* });
|
|
101
|
+
* }
|
|
102
|
+
* return await res.json();
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
declare class OAuthError extends Error {
|
|
107
|
+
/** OAuth 2.0 error code. */
|
|
108
|
+
readonly code: string;
|
|
109
|
+
/** Options controlling the OAuth error response. */
|
|
110
|
+
readonly options: OAuthErrorOptions & {
|
|
111
|
+
statusCode: number;
|
|
112
|
+
};
|
|
113
|
+
/** Human-readable description sent in the `error_description` field. */
|
|
114
|
+
readonly description: string;
|
|
115
|
+
/** HTTP status code for the error response. */
|
|
116
|
+
readonly statusCode: number;
|
|
117
|
+
/** Additional response headers. */
|
|
118
|
+
readonly headers?: Record<string, string>;
|
|
119
|
+
/** Scopes an `insufficient_scope` challenge names. */
|
|
120
|
+
readonly requiredScopes?: string[];
|
|
121
|
+
constructor(code: string, options: OAuthErrorOptions);
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
3
124
|
//#region src/ema/result.d.ts
|
|
4
125
|
|
|
5
126
|
/**
|
|
@@ -289,7 +410,7 @@ interface EmaOptions<Env = Cloudflare.Env> {
|
|
|
289
410
|
* Set to `true` to also accept public clients on this grant — for example
|
|
290
411
|
* clients registered via a Client ID Metadata Document (CIMD), which are
|
|
291
412
|
* always public (`none`) and therefore cannot present a client secret. The
|
|
292
|
-
* security trade-off is documented in
|
|
413
|
+
* security trade-off is documented in docs/advanced-configuration.md: the trust then rests on
|
|
293
414
|
* the IdP-issued, signature-verified, short-lived, single-use ID-JAG
|
|
294
415
|
* assertion (audience- and client-bound), together with the provider's
|
|
295
416
|
* configured resource pinning, rather than on a separately presented client
|
|
@@ -310,6 +431,23 @@ interface AuthorizationErrorOptions {
|
|
|
310
431
|
/** Authorization server issuer for RFC 9207 error responses. */
|
|
311
432
|
issuer?: string;
|
|
312
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* The OAuth error redirect back to a client (RFC 6749 §4.1.2.1): `error`, an optional
|
|
436
|
+
* `error_description`, the client's `state`, and `iss` (RFC 9207). Pass only a request the
|
|
437
|
+
* library validated, from `parseAuthRequest()`, `finishUpstream()` or `approveConsent()`,
|
|
438
|
+
* never one rebuilt from user input.
|
|
439
|
+
*
|
|
440
|
+
* ```ts
|
|
441
|
+
* if (new URL(req.url).searchParams.get('error')) {
|
|
442
|
+
* return Response.redirect(authorizationErrorRedirect(original, 'access_denied'), 302);
|
|
443
|
+
* }
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
declare function authorizationErrorRedirect(request: {
|
|
447
|
+
redirectUri: string;
|
|
448
|
+
state?: string;
|
|
449
|
+
issuer?: string;
|
|
450
|
+
}, code: AuthorizationErrorCode, description?: string): string;
|
|
313
451
|
/**
|
|
314
452
|
* Expected authorization-request validation failure. Absence of `redirectUri`
|
|
315
453
|
* means a caller MUST render locally and MUST NOT redirect.
|
|
@@ -320,9 +458,13 @@ declare class AuthorizationError extends Error {
|
|
|
320
458
|
readonly redirectUri?: string;
|
|
321
459
|
readonly state?: string;
|
|
322
460
|
readonly issuer?: string;
|
|
461
|
+
/**
|
|
462
|
+
* The ready-made error redirect back to the client, set only when a redirect is safe
|
|
463
|
+
* (`redirectUri` was validated). Without it, render the error locally.
|
|
464
|
+
*/
|
|
465
|
+
readonly redirectTo?: string;
|
|
323
466
|
constructor(code: AuthorizationErrorCode, options: AuthorizationErrorOptions);
|
|
324
467
|
}
|
|
325
|
-
declare function isValidOAuthScopeToken(scopeToken: string): boolean;
|
|
326
468
|
//#endregion
|
|
327
469
|
//#region src/oauth-resource-server.d.ts
|
|
328
470
|
/** RFC 9728 metadata published by a standalone OAuth resource server. */
|
|
@@ -331,7 +473,10 @@ interface OAuthResourceMetadata {
|
|
|
331
473
|
resource: string;
|
|
332
474
|
/** Authorization server issuers that can issue tokens for this resource. */
|
|
333
475
|
authorization_servers: string[];
|
|
334
|
-
/**
|
|
476
|
+
/**
|
|
477
|
+
* Minimal scopes used to access the protected resource.
|
|
478
|
+
* @deprecated Use `requiredScopes`, which this becomes on the wire. Setting both is refused.
|
|
479
|
+
*/
|
|
335
480
|
scopes_supported?: string[];
|
|
336
481
|
/** Bearer-token presentation methods. This implementation supports only `header`. */
|
|
337
482
|
bearer_methods_supported?: string[];
|
|
@@ -398,6 +543,18 @@ type OAuthResourceHandler<Env, Props> = {
|
|
|
398
543
|
interface OAuthResourceServerOptions<Env = Cloudflare.Env, Props = unknown> {
|
|
399
544
|
/** RFC 9728 metadata, including this server's one canonical resource. */
|
|
400
545
|
resourceMetadata: OAuthResourceMetadata;
|
|
546
|
+
/**
|
|
547
|
+
* The scopes required for accessing this resource (MCP: the minimal set for basic use). Published
|
|
548
|
+
* as its protected resource metadata's `scopes_supported` and named in the `401` challenge, so
|
|
549
|
+
* clients request them first; not the authorization server's catalogue, `scopesSupported`.
|
|
550
|
+
* Operations that need more ask for it with `insufficientScope()` (step-up). `offline_access` is
|
|
551
|
+
* removed automatically. Leave unset when your consent page picks the scopes.
|
|
552
|
+
*
|
|
553
|
+
* Advertised, not enforced: the handler decides whether a token is sufficient (`ctx.auth.scope`),
|
|
554
|
+
* because only it knows the deployment's scope hierarchy (a broader scope implying a narrower
|
|
555
|
+
* one), which MCP requires servers to honour.
|
|
556
|
+
*/
|
|
557
|
+
requiredScopes?: string[];
|
|
401
558
|
/** Application handler for the canonical resource URL and its path descendants. */
|
|
402
559
|
handler: OAuthResourceHandler<Env, Props>;
|
|
403
560
|
/**
|
|
@@ -409,7 +566,15 @@ interface OAuthResourceServerOptions<Env = Cloudflare.Env, Props = unknown> {
|
|
|
409
566
|
* `(env) => env.AUTH_SERVER.validateToken`
|
|
410
567
|
* - The authorization server in this Worker:
|
|
411
568
|
* `(env) => (resource, token) => authorizationServer.validateToken(resource, token, env)`
|
|
412
|
-
* - Anything else, at your own risk: a function that validates the token for `resource
|
|
569
|
+
* - Anything else, at your own risk: a function that validates the token for `resource`,
|
|
570
|
+
* such as one that recognises an upstream API's credentials and validates them itself
|
|
571
|
+
* before falling back to the authorization server.
|
|
572
|
+
*
|
|
573
|
+
* Return `null` for a token that isn't valid here (a `401` challenge). Throw an `OAuthError`
|
|
574
|
+
* for a specific answer: `temporarily_unavailable` with `statusCode: 429` and a `Retry-After`
|
|
575
|
+
* header, `insufficient_scope` with `requiredScopes`, or `invalid_token` with a description.
|
|
576
|
+
* Anything else thrown is a validator failure (`503`). An `OAuthError` thrown in another
|
|
577
|
+
* Worker arrives over RPC as a plain `Error`, so throw it in this Worker's validator.
|
|
413
578
|
*/
|
|
414
579
|
validateToken(env: Env, request: Request): OAuthResourceTokenValidator<Props>;
|
|
415
580
|
}
|
|
@@ -454,6 +619,37 @@ interface RememberConsentOptions {
|
|
|
454
619
|
*/
|
|
455
620
|
subject?: string;
|
|
456
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* What a consent page must show, per the MCP authorization spec and security best practices.
|
|
624
|
+
* Every string here may come from the client (dynamic registration or a CIMD document), so
|
|
625
|
+
* escape all of it before rendering.
|
|
626
|
+
*/
|
|
627
|
+
interface ConsentDescription {
|
|
628
|
+
clientId: string;
|
|
629
|
+
/** The client's name, or its client ID when it gave none. Self-asserted unless `clientDomain` is set. */
|
|
630
|
+
clientName: string;
|
|
631
|
+
/**
|
|
632
|
+
* For a Client ID Metadata Document client: the hostname of its HTTPS client ID, a domain the
|
|
633
|
+
* client controls. Show it prominently. Absent for registered clients, whose names are unverified.
|
|
634
|
+
*/
|
|
635
|
+
clientDomain?: string;
|
|
636
|
+
clientUri?: string;
|
|
637
|
+
logoUri?: string;
|
|
638
|
+
/** Where the tokens will be sent. */
|
|
639
|
+
redirectUri: string;
|
|
640
|
+
/**
|
|
641
|
+
* The redirect URI's hostname, which the page MUST display. A native app's private-use URI
|
|
642
|
+
* (`com.example.app:/callback`) has no host, so it's the whole URI instead.
|
|
643
|
+
*/
|
|
644
|
+
redirectHost: string;
|
|
645
|
+
/**
|
|
646
|
+
* The redirect goes to a local app (`localhost`, `127.0.0.0/8`, `::1`). The page SHOULD warn:
|
|
647
|
+
* any local process could be listening, whatever name the client claims.
|
|
648
|
+
*/
|
|
649
|
+
redirectIsLoopback: boolean;
|
|
650
|
+
/** The scopes being requested. */
|
|
651
|
+
scope: string[];
|
|
652
|
+
}
|
|
457
653
|
/** A consent page to render: post `handle` back to {@link approveConsent}; send `headers` with the page. */
|
|
458
654
|
interface ConsentTransaction {
|
|
459
655
|
handle: string;
|
|
@@ -483,19 +679,6 @@ interface ResumedUpstream<Data = unknown> {
|
|
|
483
679
|
headers: Headers;
|
|
484
680
|
}
|
|
485
681
|
//#endregion
|
|
486
|
-
//#region src/oauth-resource.d.ts
|
|
487
|
-
/** Validate an RFC 3986-safe HTTP(S) resource identifier for RFC 8707. */
|
|
488
|
-
declare function validateResourceUri(uri: string): boolean;
|
|
489
|
-
/**
|
|
490
|
-
* Whether a requested resource identifies a granted or configured resource.
|
|
491
|
-
* Only ASCII case in the URI scheme and host is ignored, and an empty path is
|
|
492
|
-
* equivalent to `/` (RFC 3986 §6.2.3), so a client that round-trips
|
|
493
|
-
* `https://example.com` through a URL parser as `https://example.com/` still
|
|
494
|
-
* names it. Port, path, query, a trailing slash after a path segment, user
|
|
495
|
-
* information, and every other byte remain significant.
|
|
496
|
-
*/
|
|
497
|
-
declare function resourceMatches(requested: string, granted: string): boolean;
|
|
498
|
-
//#endregion
|
|
499
682
|
//#region src/oauth-provider.d.ts
|
|
500
683
|
/**
|
|
501
684
|
* Enum representing OAuth grant types
|
|
@@ -552,19 +735,19 @@ interface TokenExchangeCallbackResult {
|
|
|
552
735
|
*/
|
|
553
736
|
accessTokenTTL?: number;
|
|
554
737
|
/**
|
|
555
|
-
* Override the default refresh token TTL (time-to-live) for this specific grant
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
* refresh, return
|
|
738
|
+
* Override the default refresh token TTL (time-to-live) for this specific grant, in seconds:
|
|
739
|
+
* `0` issues no refresh token, anything else must be an integer of at least 60. `undefined`
|
|
740
|
+
* keeps the provider's `refreshTokenTTL`; it never means "no expiry".
|
|
741
|
+
* Applies at authorization code exchange only and is ignored for other grant types, so one
|
|
742
|
+
* callback can return it for every grant; to extend a grant on refresh, return
|
|
743
|
+
* `refreshTokenIdleTTL`.
|
|
560
744
|
*/
|
|
561
745
|
refreshTokenTTL?: number;
|
|
562
746
|
/**
|
|
563
747
|
* Idle lifetime for this grant's refresh token, in seconds from this refresh. The
|
|
564
|
-
* grant then expires that long after this refresh unless it is refreshed again.
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
* for this refresh.
|
|
748
|
+
* grant then expires that long after this refresh unless it is refreshed again. Applies to
|
|
749
|
+
* refresh token exchange only and is ignored for other grant types. Overrides the provider's
|
|
750
|
+
* `refreshTokenIdleTTL` for this refresh.
|
|
568
751
|
*
|
|
569
752
|
* Useful when the Worker is itself an OAuth client and has just rotated an upstream
|
|
570
753
|
* refresh token: return the upstream lifetime and the grant lives exactly as long as
|
|
@@ -588,7 +771,7 @@ interface TokenExchangeCallbackResult {
|
|
|
588
771
|
/**
|
|
589
772
|
* Options for token exchange callback functions
|
|
590
773
|
*/
|
|
591
|
-
interface TokenExchangeCallbackOptions {
|
|
774
|
+
interface TokenExchangeCallbackOptions<Env = Cloudflare.Env> {
|
|
592
775
|
/**
|
|
593
776
|
* The type of grant being processed.
|
|
594
777
|
*/
|
|
@@ -631,6 +814,11 @@ interface TokenExchangeCallbackOptions {
|
|
|
631
814
|
* Application-specific properties currently associated with this grant
|
|
632
815
|
*/
|
|
633
816
|
props: any;
|
|
817
|
+
/**
|
|
818
|
+
* The Worker's environment for this request, so the callback can reach secrets and bindings
|
|
819
|
+
* (an upstream provider's client secret, say) without the provider being rebuilt per request.
|
|
820
|
+
*/
|
|
821
|
+
env: Env;
|
|
634
822
|
}
|
|
635
823
|
/**
|
|
636
824
|
* Options for the client registration callback (RFC 7591).
|
|
@@ -728,7 +916,10 @@ interface OAuthProtectedResourceMetadata {
|
|
|
728
916
|
* issuer.
|
|
729
917
|
*/
|
|
730
918
|
authorization_servers?: string[];
|
|
731
|
-
/**
|
|
919
|
+
/**
|
|
920
|
+
* Minimal scopes required for basic protected-resource functionality.
|
|
921
|
+
* @deprecated Use `requiredScopes`, which this becomes on the wire. Setting both is refused.
|
|
922
|
+
*/
|
|
732
923
|
scopes_supported?: string[];
|
|
733
924
|
/** Methods by which bearer tokens can be presented. Defaults to `["header"]`. */
|
|
734
925
|
bearer_methods_supported?: string[];
|
|
@@ -800,6 +991,7 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
800
991
|
* Defaults to 30 days (2,592,000 seconds).
|
|
801
992
|
* Set to 0 to disable refresh tokens entirely.
|
|
802
993
|
* Set to `undefined` explicitly for refresh tokens that never expire.
|
|
994
|
+
* Anything else must be an integer of at least 60 seconds (Cloudflare KV's minimum expiration window).
|
|
803
995
|
* For example: 3600 = 1 hour, 2592000 = 30 days
|
|
804
996
|
*/
|
|
805
997
|
refreshTokenTTL?: number;
|
|
@@ -820,27 +1012,16 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
820
1012
|
* Defaults to 90 days (7,776,000 seconds).
|
|
821
1013
|
* Clients created via the DCR endpoint will automatically expire after this duration.
|
|
822
1014
|
* Clients created via `OAuthHelpers.createClient()` are not affected by this setting.
|
|
823
|
-
* Set to `undefined` explicitly for clients that never expire
|
|
1015
|
+
* Set to `undefined` explicitly for clients that never expire; otherwise an integer of at
|
|
1016
|
+
* least 60 seconds (Cloudflare KV's minimum expiration window).
|
|
824
1017
|
*/
|
|
825
1018
|
clientRegistrationTTL?: number;
|
|
826
1019
|
/**
|
|
827
1020
|
* Scopes supported by the authorization server.
|
|
828
|
-
* These are advertised only in authorization server metadata; configure
|
|
829
|
-
*
|
|
1021
|
+
* These are advertised only in authorization server metadata; configure a resource's
|
|
1022
|
+
* required scopes separately, with `requiredScopes`.
|
|
830
1023
|
*/
|
|
831
1024
|
scopesSupported?: string[];
|
|
832
|
-
/**
|
|
833
|
-
* Controls whether the OAuth implicit flow is allowed.
|
|
834
|
-
* This flow is discouraged in OAuth 2.1 due to security concerns.
|
|
835
|
-
* Defaults to false.
|
|
836
|
-
*/
|
|
837
|
-
allowImplicitFlow?: boolean;
|
|
838
|
-
/**
|
|
839
|
-
* Controls whether the legacy plain PKCE method is allowed.
|
|
840
|
-
* Defaults to false so PKCE challenges use S256 exclusively.
|
|
841
|
-
* Set to true only for compatibility with clients that cannot use S256.
|
|
842
|
-
*/
|
|
843
|
-
allowPlainPKCE?: boolean;
|
|
844
1025
|
/**
|
|
845
1026
|
* Controls whether OAuth 2.0 Token Exchange (RFC 8693) is allowed.
|
|
846
1027
|
* When false, the token exchange grant type will not be advertised in metadata
|
|
@@ -878,7 +1059,7 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
878
1059
|
* The callback can return new props values that will be stored with the token or grant.
|
|
879
1060
|
* If the callback returns nothing or undefined for a props field, the original props will be used.
|
|
880
1061
|
*/
|
|
881
|
-
tokenExchangeCallback?: (options: TokenExchangeCallbackOptions) => Promise<TokenExchangeCallbackResult | void> | TokenExchangeCallbackResult | void;
|
|
1062
|
+
tokenExchangeCallback?: (options: TokenExchangeCallbackOptions<Env>) => Promise<TokenExchangeCallbackResult | void> | TokenExchangeCallbackResult | void;
|
|
882
1063
|
/**
|
|
883
1064
|
* Optional callback called when a provided bearer credential was not found
|
|
884
1065
|
* in the internal KV. It can validate an external OAuth access token, opaque
|
|
@@ -916,6 +1097,14 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
916
1097
|
internal: OAuthErrorInternal;
|
|
917
1098
|
request?: Request;
|
|
918
1099
|
}) => Response | void;
|
|
1100
|
+
/**
|
|
1101
|
+
* Let authorization requests use RFC 8252 private-use URI scheme redirect URIs (for example
|
|
1102
|
+
* `com.example.app:/oauth`), for native apps. By default a request's redirect URI must use
|
|
1103
|
+
* `https`, or `http` on a loopback host, as MCP and OAuth 2.1 require; remote `http` is never
|
|
1104
|
+
* accepted. Without this option a client can still register private-use URIs next to a compliant
|
|
1105
|
+
* one (Cursor does), but no request can use them.
|
|
1106
|
+
*/
|
|
1107
|
+
allowPrivateUseRedirectUris?: boolean;
|
|
919
1108
|
/**
|
|
920
1109
|
* Explicitly enable Client ID Metadata Document (CIMD) support.
|
|
921
1110
|
* When true, URL-formatted client_ids will be fetched as metadata documents.
|
|
@@ -934,6 +1123,18 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
934
1123
|
* Controls the response served at /.well-known/oauth-protected-resource.
|
|
935
1124
|
*/
|
|
936
1125
|
resourceMetadata: OAuthProtectedResourceMetadata;
|
|
1126
|
+
/**
|
|
1127
|
+
* The scopes required for accessing this resource (MCP: the minimal set for basic use). Published
|
|
1128
|
+
* as its protected resource metadata's `scopes_supported` and named in the `401` challenge, so
|
|
1129
|
+
* clients request them first; not the authorization server's catalogue, `scopesSupported`.
|
|
1130
|
+
* Operations that need more ask for it with `insufficientScope()` (step-up). `offline_access` is
|
|
1131
|
+
* removed automatically. Leave unset when your consent page picks the scopes.
|
|
1132
|
+
*
|
|
1133
|
+
* Advertised, not enforced: the handler decides whether a token is sufficient (`ctx.auth.scope`),
|
|
1134
|
+
* because only it knows the deployment's scope hierarchy (a broader scope implying a narrower
|
|
1135
|
+
* one), which MCP requires servers to honour.
|
|
1136
|
+
*/
|
|
1137
|
+
requiredScopes?: string[];
|
|
937
1138
|
}
|
|
938
1139
|
/**
|
|
939
1140
|
* Functional authorization-server surface for the role-based API.
|
|
@@ -941,9 +1142,20 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
941
1142
|
* `getOAuthApi()` to parse and complete it; `fetch()` serves protocol-owned AS
|
|
942
1143
|
* endpoints such as metadata, token, revocation, and optional registration.
|
|
943
1144
|
*/
|
|
944
|
-
type OAuthAuthorizationServerOptions<Env = Cloudflare.Env> = Omit<OAuthProviderOptions<Env>, 'apiRoute' | 'apiHandler' | 'apiHandlers' | 'defaultHandler' | 'resourceMetadata' | 'resolveExternalToken'> & {
|
|
1145
|
+
type OAuthAuthorizationServerOptions<Env = Cloudflare.Env> = Omit<OAuthProviderOptions<Env>, 'apiRoute' | 'apiHandler' | 'apiHandlers' | 'defaultHandler' | 'authorizeEndpoint' | 'tokenEndpoint' | 'resourceMetadata' | 'requiredScopes' | 'resolveExternalToken'> & {
|
|
945
1146
|
/** Canonical RFC 8414 issuer. */
|
|
946
1147
|
issuer: string;
|
|
1148
|
+
/**
|
|
1149
|
+
* Your authorization endpoint, advertised in metadata. Route it before calling `fetch()`;
|
|
1150
|
+
* `parseAuthRequest()` rejects requests that arrive anywhere else, so a mismatch fails on the
|
|
1151
|
+
* first request. Defaults to `${issuer}/authorize`. A path is on the issuer's origin.
|
|
1152
|
+
*/
|
|
1153
|
+
authorizeEndpoint?: string;
|
|
1154
|
+
/**
|
|
1155
|
+
* The token endpoint, which also handles revocation, served by `fetch()` and advertised in
|
|
1156
|
+
* metadata. Defaults to `${issuer}/oauth/token`. A path is on the issuer's origin.
|
|
1157
|
+
*/
|
|
1158
|
+
tokenEndpoint?: string;
|
|
947
1159
|
/**
|
|
948
1160
|
* Canonical identifiers of every protected resource this authorization server issues
|
|
949
1161
|
* tokens for, whether hosted in this Worker through `OAuthResourceServer` or by another
|
|
@@ -1006,6 +1218,13 @@ interface OAuthHelpers {
|
|
|
1006
1218
|
completeAuthorization(options: CompleteAuthorizationOptions): Promise<{
|
|
1007
1219
|
redirectTo: string;
|
|
1008
1220
|
}>;
|
|
1221
|
+
/**
|
|
1222
|
+
* The facts a consent page must show for a request: the client's name (and, for a Client ID
|
|
1223
|
+
* Metadata Document client, its verified domain), the redirect URI's hostname, whether it goes
|
|
1224
|
+
* to a local app, and the scopes. Every string may come from the client: escape it.
|
|
1225
|
+
* @throws CimdFetchError when the client's metadata document cannot be resolved
|
|
1226
|
+
*/
|
|
1227
|
+
describeConsent(authRequest: AuthRequest): Promise<ConsentDescription>;
|
|
1009
1228
|
/**
|
|
1010
1229
|
* Whether an approval remembered by `approveConsent(…, { remember })` covers this request: the
|
|
1011
1230
|
* same client, redirect URI and resource, asking for a subset of the approved scopes. Pass the
|
|
@@ -1066,16 +1285,28 @@ interface OAuthHelpers {
|
|
|
1066
1285
|
*/
|
|
1067
1286
|
listClients(options?: ListOptions): Promise<ListResult<ClientInfo>>;
|
|
1068
1287
|
/**
|
|
1069
|
-
* Updates an existing OAuth client
|
|
1288
|
+
* Updates an existing OAuth client. Redirect URIs, grant types and response types are held to
|
|
1289
|
+
* the same rules as registration. Client ID Metadata Document clients can't be updated here:
|
|
1290
|
+
* their document owns their metadata.
|
|
1070
1291
|
* @param clientId - The ID of the client to update
|
|
1071
1292
|
* @param updates - Partial client information with fields to update
|
|
1072
1293
|
* @returns A Promise resolving to the updated client info, or null if not found
|
|
1294
|
+
* @throws Error when an update breaks the redirect URI policy or names an unsupported grant or response type
|
|
1295
|
+
* @throws TypeError for a Client ID Metadata Document client while CIMD is enabled
|
|
1073
1296
|
*/
|
|
1074
1297
|
updateClient(clientId: string, updates: Partial<ClientInfo>): Promise<ClientInfo | null>;
|
|
1075
1298
|
/**
|
|
1076
|
-
* Deletes an OAuth client
|
|
1299
|
+
* Deletes an OAuth client, then revokes its grants and tokens across all users. The client
|
|
1300
|
+
* can no longer authenticate, authorize or refresh as soon as the call starts. Access tokens
|
|
1301
|
+
* it already holds stay valid until revocation reaches them or they expire (`accessTokenTTL`):
|
|
1302
|
+
* validating an access token reads only the token record, never the client. If revocation is
|
|
1303
|
+
* cut short (for example by a subrequest limit on a very large namespace), the call throws;
|
|
1304
|
+
* call it again to continue, and `purgeExpiredData()` also removes the leftovers, which are
|
|
1305
|
+
* orphaned grants by then.
|
|
1306
|
+
* For a Client ID Metadata Document client there is no stored record: this revokes its grants,
|
|
1307
|
+
* and the client can authorize again as long as its document resolves.
|
|
1077
1308
|
* @param clientId - The ID of the client to delete
|
|
1078
|
-
* @returns A Promise resolving when the
|
|
1309
|
+
* @returns A Promise resolving when the client and all its grants are gone.
|
|
1079
1310
|
*/
|
|
1080
1311
|
deleteClient(clientId: string): Promise<void>;
|
|
1081
1312
|
/**
|
|
@@ -1279,7 +1510,9 @@ interface CompleteAuthorizationOptions {
|
|
|
1279
1510
|
*/
|
|
1280
1511
|
request: AuthRequest;
|
|
1281
1512
|
/**
|
|
1282
|
-
* Identifier for the user granting the authorization
|
|
1513
|
+
* Identifier for the user granting the authorization. Must be non-empty and must not contain
|
|
1514
|
+
* `:`, which separates the parts of issued tokens and storage keys; encode namespaced or
|
|
1515
|
+
* composite IDs first (for example `encodeURIComponent('tenant:user')`).
|
|
1283
1516
|
*/
|
|
1284
1517
|
userId: string;
|
|
1285
1518
|
/**
|
|
@@ -1302,15 +1535,6 @@ interface CompleteAuthorizationOptions {
|
|
|
1302
1535
|
* Set to false to allow multiple concurrent grants per user+client.
|
|
1303
1536
|
*/
|
|
1304
1537
|
revokeExistingGrants?: boolean;
|
|
1305
|
-
/**
|
|
1306
|
-
* How many grants written by a version before 1.0 are read at once while
|
|
1307
|
-
* revoking existing grants. Grants written by 1.0 or later carry their client,
|
|
1308
|
-
* resource and redirect URI as KV key metadata and are matched from `list()`
|
|
1309
|
-
* without being read, so this only bounds the fan-out for older grants. Only
|
|
1310
|
-
* used when revokeExistingGrants is not false. Must be a positive integer;
|
|
1311
|
-
* values above 1000 are clamped. Defaults to 50.
|
|
1312
|
-
*/
|
|
1313
|
-
revokeExistingGrantsBatchSize?: number;
|
|
1314
1538
|
}
|
|
1315
1539
|
/**
|
|
1316
1540
|
* Authorization grant record
|
|
@@ -1467,7 +1691,8 @@ interface Token extends TokenBase {
|
|
|
1467
1691
|
*/
|
|
1468
1692
|
grant: {
|
|
1469
1693
|
/**
|
|
1470
|
-
* Client
|
|
1694
|
+
* Client this token was issued to: the grant's client, or, for a token from an allowed
|
|
1695
|
+
* cross-client token exchange, the client that requested it (RFC 8693).
|
|
1471
1696
|
*/
|
|
1472
1697
|
clientId: string;
|
|
1473
1698
|
/**
|
|
@@ -1490,7 +1715,8 @@ interface TokenSummary<T = any> extends TokenBase {
|
|
|
1490
1715
|
*/
|
|
1491
1716
|
grant: {
|
|
1492
1717
|
/**
|
|
1493
|
-
* Client
|
|
1718
|
+
* Client this token was issued to: the grant's client, or, for a token from an allowed
|
|
1719
|
+
* cross-client token exchange, the client that requested it (RFC 8693).
|
|
1494
1720
|
*/
|
|
1495
1721
|
clientId: string;
|
|
1496
1722
|
/**
|
|
@@ -1562,6 +1788,12 @@ interface PurgeOptions {
|
|
|
1562
1788
|
* Defaults to true.
|
|
1563
1789
|
*/
|
|
1564
1790
|
purgeOrphanedTokens?: boolean;
|
|
1791
|
+
/**
|
|
1792
|
+
* Where to resume: the `cursor` from the previous invocation's result. Omit it to start
|
|
1793
|
+
* a new sweep. Persist the returned cursor between invocations (for example in KV), or
|
|
1794
|
+
* every invocation re-checks the same first `batchSize` records.
|
|
1795
|
+
*/
|
|
1796
|
+
cursor?: string;
|
|
1565
1797
|
}
|
|
1566
1798
|
/**
|
|
1567
1799
|
* Result of a purgeExpiredData garbage collection invocation
|
|
@@ -1575,8 +1807,10 @@ interface PurgeResult {
|
|
|
1575
1807
|
tokensChecked: number;
|
|
1576
1808
|
/** Number of token records purged (orphaned) */
|
|
1577
1809
|
tokensPurged: number;
|
|
1578
|
-
/** True
|
|
1810
|
+
/** True once the sweep has covered both key spaces; there is no `cursor` then. */
|
|
1579
1811
|
done: boolean;
|
|
1812
|
+
/** Pass as `PurgeOptions.cursor` to the next invocation to continue this sweep. Absent when `done`. */
|
|
1813
|
+
cursor?: string;
|
|
1580
1814
|
}
|
|
1581
1815
|
/**
|
|
1582
1816
|
* Public representation of a grant, with sensitive data removed
|
|
@@ -1700,108 +1934,6 @@ declare function getOAuthApi<Env = Cloudflare.Env>(options: OAuthProviderOptions
|
|
|
1700
1934
|
* Error class for OAuth operations
|
|
1701
1935
|
* Carries OAuth error code and description for proper error responses
|
|
1702
1936
|
*/
|
|
1703
|
-
/**
|
|
1704
|
-
* The internal reason behind an error response, forwarded to the `onError` hook and never
|
|
1705
|
-
* placed on the wire. `category` is a stable kebab-case subsystem (`client-authentication`,
|
|
1706
|
-
* `authorization-code-grant`, `refresh-token-grant`, `token-exchange-grant`,
|
|
1707
|
-
* `token-endpoint-request`, `token-revocation`, `token-issuance`, `resource-indicator`,
|
|
1708
|
-
* `client-registration`, `client-id-metadata-document`, `protected-resource`,
|
|
1709
|
-
* `enterprise-managed-authorization`, `token-exchange-callback`); `reason` is a stable
|
|
1710
|
-
* snake_case slug naming the exact check that failed. Treat both like enum members in semver.
|
|
1711
|
-
* `detail` may carry structured context such as a caught error; it is never a secret.
|
|
1712
|
-
*/
|
|
1713
|
-
interface OAuthErrorInternal {
|
|
1714
|
-
/** Stable kebab-case subsystem that produced the error. */
|
|
1715
|
-
category: string;
|
|
1716
|
-
/** Stable snake_case slug naming the failed check, often more specific than the wire description. */
|
|
1717
|
-
reason: string;
|
|
1718
|
-
/** Optional structured context, e.g. the caught error or the offending parameter. */
|
|
1719
|
-
detail?: unknown;
|
|
1720
|
-
}
|
|
1721
|
-
/**
|
|
1722
|
-
* Options accepted by the {@link OAuthError} constructor.
|
|
1723
|
-
*/
|
|
1724
|
-
interface OAuthErrorOptions {
|
|
1725
|
-
/**
|
|
1726
|
-
* Human-readable text returned in the `error_description` field.
|
|
1727
|
-
*/
|
|
1728
|
-
description: string;
|
|
1729
|
-
/**
|
|
1730
|
-
* HTTP status code for the error response. Defaults to `400`.
|
|
1731
|
-
*/
|
|
1732
|
-
statusCode?: number;
|
|
1733
|
-
/**
|
|
1734
|
-
* Additional response headers.
|
|
1735
|
-
*
|
|
1736
|
-
* For transient failures (e.g. upstream rate limits), set
|
|
1737
|
-
* `Retry-After` here so well-behaved clients back off instead of
|
|
1738
|
-
* retry-storming. Per RFC 7231 §7.1.3 the value may be either a
|
|
1739
|
-
* number of seconds or an HTTP-date.
|
|
1740
|
-
*/
|
|
1741
|
-
headers?: Record<string, string>;
|
|
1742
|
-
/**
|
|
1743
|
-
* Internal reason forwarded to the `onError` hook and never sent on the wire. The library
|
|
1744
|
-
* sets it on every error it originates; a `tokenExchangeCallback` may set its own. An
|
|
1745
|
-
* `OAuthError` thrown without one reaches `onError` as
|
|
1746
|
-
* `{ category: 'token-exchange-callback', reason: 'callback_error', detail: error }`.
|
|
1747
|
-
*/
|
|
1748
|
-
internal?: OAuthErrorInternal;
|
|
1749
|
-
}
|
|
1750
|
-
/**
|
|
1751
|
-
* Structured OAuth 2.0 token-endpoint error.
|
|
1752
|
-
*
|
|
1753
|
-
* Throw from a `tokenExchangeCallback` or any code it calls to surface a
|
|
1754
|
-
* standard OAuth token response (`{ error, error_description }`) instead of a
|
|
1755
|
-
* generic `500 Internal Server Error`.
|
|
1756
|
-
*
|
|
1757
|
-
* Anything thrown that is **not** an `OAuthError` continues to surface as
|
|
1758
|
-
* a 500 so unexpected failures remain visible — the provider does not
|
|
1759
|
-
* catch-everything-and-return-400.
|
|
1760
|
-
*
|
|
1761
|
-
* @example
|
|
1762
|
-
* ```ts
|
|
1763
|
-
* import { OAuthError } from '@cloudflare/workers-oauth-provider';
|
|
1764
|
-
*
|
|
1765
|
-
* tokenExchangeCallback: async (options) => {
|
|
1766
|
-
* if (options.grantType === 'refresh_token') {
|
|
1767
|
-
* // refreshUpstream() may throw OAuthError from any depth
|
|
1768
|
-
* return { newProps: await refreshUpstream(options.props) };
|
|
1769
|
-
* }
|
|
1770
|
-
* }
|
|
1771
|
-
*
|
|
1772
|
-
* async function refreshUpstream(props) {
|
|
1773
|
-
* const res = await fetch(...);
|
|
1774
|
-
* if (res.status === 401) {
|
|
1775
|
-
* // invalid_grant can never recover: the provider also revokes this grant and its tokens.
|
|
1776
|
-
* throw new OAuthError('invalid_grant', { description: 'upstream refresh token is invalid' });
|
|
1777
|
-
* }
|
|
1778
|
-
* if (res.status === 429) {
|
|
1779
|
-
* // Mirror upstream's Retry-After if present, otherwise pick a default.
|
|
1780
|
-
* throw new OAuthError('temporarily_unavailable', {
|
|
1781
|
-
* description: 'upstream rate limited',
|
|
1782
|
-
* statusCode: 429,
|
|
1783
|
-
* headers: { 'Retry-After': res.headers.get('retry-after') ?? '60' },
|
|
1784
|
-
* });
|
|
1785
|
-
* }
|
|
1786
|
-
* return await res.json();
|
|
1787
|
-
* }
|
|
1788
|
-
* ```
|
|
1789
|
-
*/
|
|
1790
|
-
declare class OAuthError extends Error {
|
|
1791
|
-
/** OAuth 2.0 error code. */
|
|
1792
|
-
readonly code: string;
|
|
1793
|
-
/** Options controlling the OAuth error response. */
|
|
1794
|
-
readonly options: OAuthErrorOptions & {
|
|
1795
|
-
statusCode: number;
|
|
1796
|
-
};
|
|
1797
|
-
/** Human-readable description sent in the `error_description` field. */
|
|
1798
|
-
readonly description: string;
|
|
1799
|
-
/** HTTP status code for the error response. */
|
|
1800
|
-
readonly statusCode: number;
|
|
1801
|
-
/** Additional response headers. */
|
|
1802
|
-
readonly headers?: Record<string, string>;
|
|
1803
|
-
constructor(code: string, options: OAuthErrorOptions);
|
|
1804
|
-
}
|
|
1805
1937
|
/** Options accepted by the {@link ExternalTokenError} constructor. */
|
|
1806
1938
|
interface ExternalTokenErrorOptions {
|
|
1807
1939
|
/**
|
|
@@ -1878,20 +2010,5 @@ declare class CimdFetchError extends Error {
|
|
|
1878
2010
|
*/
|
|
1879
2011
|
constructor(metadataUrl: string, cause: unknown);
|
|
1880
2012
|
}
|
|
1881
|
-
/**
|
|
1882
|
-
* Decodes a base64url-encoded string to bytes.
|
|
1883
|
-
*/
|
|
1884
|
-
declare function base64UrlToBytes(base64Url: string): Uint8Array;
|
|
1885
|
-
/**
|
|
1886
|
-
* Parses a base64url-encoded JWT JSON part into an object.
|
|
1887
|
-
*/
|
|
1888
|
-
declare function parseJwtJsonPart(encoded: string): Record<string, unknown>;
|
|
1889
|
-
/**
|
|
1890
|
-
* Gets WebCrypto import and verify parameters for supported JOSE algorithms.
|
|
1891
|
-
*/
|
|
1892
|
-
declare function getJwtCryptoAlgorithms(alg: string): {
|
|
1893
|
-
importAlgorithm: Parameters<SubtleCrypto['importKey']>[2];
|
|
1894
|
-
verifyAlgorithm: Parameters<SubtleCrypto['verify']>[0];
|
|
1895
|
-
};
|
|
1896
2013
|
//#endregion
|
|
1897
|
-
export { type ApprovedConsent, AuthRequest, AuthorizationError, type AuthorizationErrorCode, type AuthorizationErrorOptions, AuthorizationServerBinding, CimdFetchError, ClientInfo, ClientRegistrationCallbackOptions, ClientRegistrationCallbackResult, CompleteAuthorizationOptions, type ConsentTransaction, type DeniedConsent, type EmaClaimsMapper, type EmaClaimsMapperInput, type EmaClaimsMapperResult, type EmaIdJagClaims, type EmaOptions, type EmaTrustedIssuer, type EmaTrustedIssuerResolver, type EmaTrustedIssuerResolverInput, type EmaValidationError, ExchangeTokenOptions, ExternalTokenError, ExternalTokenErrorOptions, Grant, GrantSummary, GrantType, ListOptions, ListResult, OAuthAuthorizationServer, OAuthAuthorizationServerOptions, OAuthError, OAuthErrorInternal, OAuthErrorOptions, OAuthHelpers, OAuthProtectedResourceMetadata, OAuthProvider, OAuthProvider as default, OAuthProviderOptions, OAuthResourceAuth, OAuthResourceContext, OAuthResourceHandler, OAuthResourceMetadata, OAuthResourceServer, OAuthResourceServerOptions, OAuthResourceTokenValidation, OAuthResourceTokenValidator, OAuthTokenErrorCode, PurgeOptions, PurgeResult, type RememberConsentOptions, ResolveExternalTokenInput, ResolveExternalTokenResult, type ResumedUpstream, Token, TokenBase, TokenExchangeCallbackOptions, TokenExchangeCallbackResult, TokenSummary, type UpstreamTransaction, ValidatedAccessToken,
|
|
2014
|
+
export { type ApprovedConsent, AuthRequest, AuthorizationError, type AuthorizationErrorCode, type AuthorizationErrorOptions, AuthorizationServerBinding, CimdFetchError, ClientInfo, ClientRegistrationCallbackOptions, ClientRegistrationCallbackResult, CompleteAuthorizationOptions, type ConsentDescription, type ConsentTransaction, type DeniedConsent, type EmaClaimsMapper, type EmaClaimsMapperInput, type EmaClaimsMapperResult, type EmaIdJagClaims, type EmaOptions, type EmaTrustedIssuer, type EmaTrustedIssuerResolver, type EmaTrustedIssuerResolverInput, type EmaValidationError, ExchangeTokenOptions, ExternalTokenError, ExternalTokenErrorOptions, Grant, GrantSummary, GrantType, ListOptions, ListResult, OAuthAuthorizationServer, OAuthAuthorizationServerOptions, OAuthError, type OAuthErrorInternal, type OAuthErrorOptions, OAuthHelpers, OAuthProtectedResourceMetadata, OAuthProvider, OAuthProvider as default, OAuthProviderOptions, OAuthResourceAuth, OAuthResourceContext, OAuthResourceHandler, OAuthResourceMetadata, OAuthResourceServer, OAuthResourceServerOptions, OAuthResourceTokenValidation, OAuthResourceTokenValidator, OAuthTokenErrorCode, PurgeOptions, PurgeResult, type RememberConsentOptions, ResolveExternalTokenInput, ResolveExternalTokenResult, type ResumedUpstream, Token, TokenBase, TokenExchangeCallbackOptions, TokenExchangeCallbackResult, TokenSummary, type UpstreamTransaction, ValidatedAccessToken, authorizationErrorRedirect, getOAuthApi, insufficientScope };
|