@cloudflare/workers-oauth-provider 1.1.0 → 1.2.0
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 +294 -179
- package/dist/oauth-provider.js +717 -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,12 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
916
1097
|
internal: OAuthErrorInternal;
|
|
917
1098
|
request?: Request;
|
|
918
1099
|
}) => Response | void;
|
|
1100
|
+
/**
|
|
1101
|
+
* Accept RFC 8252 private-use URI scheme redirect URIs (for example `com.example.app:/oauth`)
|
|
1102
|
+
* for native apps. By default redirect URIs must use `https`, or `http` on a loopback host, as
|
|
1103
|
+
* MCP and OAuth 2.1 require; remote `http` is never accepted. Leave this off for MCP servers.
|
|
1104
|
+
*/
|
|
1105
|
+
allowPrivateUseRedirectUris?: boolean;
|
|
919
1106
|
/**
|
|
920
1107
|
* Explicitly enable Client ID Metadata Document (CIMD) support.
|
|
921
1108
|
* When true, URL-formatted client_ids will be fetched as metadata documents.
|
|
@@ -934,6 +1121,18 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
934
1121
|
* Controls the response served at /.well-known/oauth-protected-resource.
|
|
935
1122
|
*/
|
|
936
1123
|
resourceMetadata: OAuthProtectedResourceMetadata;
|
|
1124
|
+
/**
|
|
1125
|
+
* The scopes required for accessing this resource (MCP: the minimal set for basic use). Published
|
|
1126
|
+
* as its protected resource metadata's `scopes_supported` and named in the `401` challenge, so
|
|
1127
|
+
* clients request them first; not the authorization server's catalogue, `scopesSupported`.
|
|
1128
|
+
* Operations that need more ask for it with `insufficientScope()` (step-up). `offline_access` is
|
|
1129
|
+
* removed automatically. Leave unset when your consent page picks the scopes.
|
|
1130
|
+
*
|
|
1131
|
+
* Advertised, not enforced: the handler decides whether a token is sufficient (`ctx.auth.scope`),
|
|
1132
|
+
* because only it knows the deployment's scope hierarchy (a broader scope implying a narrower
|
|
1133
|
+
* one), which MCP requires servers to honour.
|
|
1134
|
+
*/
|
|
1135
|
+
requiredScopes?: string[];
|
|
937
1136
|
}
|
|
938
1137
|
/**
|
|
939
1138
|
* Functional authorization-server surface for the role-based API.
|
|
@@ -941,9 +1140,20 @@ interface OAuthProviderOptions<Env = Cloudflare.Env> {
|
|
|
941
1140
|
* `getOAuthApi()` to parse and complete it; `fetch()` serves protocol-owned AS
|
|
942
1141
|
* endpoints such as metadata, token, revocation, and optional registration.
|
|
943
1142
|
*/
|
|
944
|
-
type OAuthAuthorizationServerOptions<Env = Cloudflare.Env> = Omit<OAuthProviderOptions<Env>, 'apiRoute' | 'apiHandler' | 'apiHandlers' | 'defaultHandler' | 'resourceMetadata' | 'resolveExternalToken'> & {
|
|
1143
|
+
type OAuthAuthorizationServerOptions<Env = Cloudflare.Env> = Omit<OAuthProviderOptions<Env>, 'apiRoute' | 'apiHandler' | 'apiHandlers' | 'defaultHandler' | 'authorizeEndpoint' | 'tokenEndpoint' | 'resourceMetadata' | 'requiredScopes' | 'resolveExternalToken'> & {
|
|
945
1144
|
/** Canonical RFC 8414 issuer. */
|
|
946
1145
|
issuer: string;
|
|
1146
|
+
/**
|
|
1147
|
+
* Your authorization endpoint, advertised in metadata. Route it before calling `fetch()`;
|
|
1148
|
+
* `parseAuthRequest()` rejects requests that arrive anywhere else, so a mismatch fails on the
|
|
1149
|
+
* first request. Defaults to `${issuer}/authorize`. A path is on the issuer's origin.
|
|
1150
|
+
*/
|
|
1151
|
+
authorizeEndpoint?: string;
|
|
1152
|
+
/**
|
|
1153
|
+
* The token endpoint, which also handles revocation, served by `fetch()` and advertised in
|
|
1154
|
+
* metadata. Defaults to `${issuer}/oauth/token`. A path is on the issuer's origin.
|
|
1155
|
+
*/
|
|
1156
|
+
tokenEndpoint?: string;
|
|
947
1157
|
/**
|
|
948
1158
|
* Canonical identifiers of every protected resource this authorization server issues
|
|
949
1159
|
* tokens for, whether hosted in this Worker through `OAuthResourceServer` or by another
|
|
@@ -1006,6 +1216,13 @@ interface OAuthHelpers {
|
|
|
1006
1216
|
completeAuthorization(options: CompleteAuthorizationOptions): Promise<{
|
|
1007
1217
|
redirectTo: string;
|
|
1008
1218
|
}>;
|
|
1219
|
+
/**
|
|
1220
|
+
* The facts a consent page must show for a request: the client's name (and, for a Client ID
|
|
1221
|
+
* Metadata Document client, its verified domain), the redirect URI's hostname, whether it goes
|
|
1222
|
+
* to a local app, and the scopes. Every string may come from the client: escape it.
|
|
1223
|
+
* @throws CimdFetchError when the client's metadata document cannot be resolved
|
|
1224
|
+
*/
|
|
1225
|
+
describeConsent(authRequest: AuthRequest): Promise<ConsentDescription>;
|
|
1009
1226
|
/**
|
|
1010
1227
|
* Whether an approval remembered by `approveConsent(…, { remember })` covers this request: the
|
|
1011
1228
|
* same client, redirect URI and resource, asking for a subset of the approved scopes. Pass the
|
|
@@ -1066,16 +1283,28 @@ interface OAuthHelpers {
|
|
|
1066
1283
|
*/
|
|
1067
1284
|
listClients(options?: ListOptions): Promise<ListResult<ClientInfo>>;
|
|
1068
1285
|
/**
|
|
1069
|
-
* Updates an existing OAuth client
|
|
1286
|
+
* Updates an existing OAuth client. Redirect URIs, grant types and response types are held to
|
|
1287
|
+
* the same rules as registration. Client ID Metadata Document clients can't be updated here:
|
|
1288
|
+
* their document owns their metadata.
|
|
1070
1289
|
* @param clientId - The ID of the client to update
|
|
1071
1290
|
* @param updates - Partial client information with fields to update
|
|
1072
1291
|
* @returns A Promise resolving to the updated client info, or null if not found
|
|
1292
|
+
* @throws Error when an update breaks the redirect URI policy or names an unsupported grant or response type
|
|
1293
|
+
* @throws TypeError for a Client ID Metadata Document client while CIMD is enabled
|
|
1073
1294
|
*/
|
|
1074
1295
|
updateClient(clientId: string, updates: Partial<ClientInfo>): Promise<ClientInfo | null>;
|
|
1075
1296
|
/**
|
|
1076
|
-
* Deletes an OAuth client
|
|
1297
|
+
* Deletes an OAuth client, then revokes its grants and tokens across all users. The client
|
|
1298
|
+
* can no longer authenticate, authorize or refresh as soon as the call starts. Access tokens
|
|
1299
|
+
* it already holds stay valid until revocation reaches them or they expire (`accessTokenTTL`):
|
|
1300
|
+
* validating an access token reads only the token record, never the client. If revocation is
|
|
1301
|
+
* cut short (for example by a subrequest limit on a very large namespace), the call throws;
|
|
1302
|
+
* call it again to continue, and `purgeExpiredData()` also removes the leftovers, which are
|
|
1303
|
+
* orphaned grants by then.
|
|
1304
|
+
* For a Client ID Metadata Document client there is no stored record: this revokes its grants,
|
|
1305
|
+
* and the client can authorize again as long as its document resolves.
|
|
1077
1306
|
* @param clientId - The ID of the client to delete
|
|
1078
|
-
* @returns A Promise resolving when the
|
|
1307
|
+
* @returns A Promise resolving when the client and all its grants are gone.
|
|
1079
1308
|
*/
|
|
1080
1309
|
deleteClient(clientId: string): Promise<void>;
|
|
1081
1310
|
/**
|
|
@@ -1279,7 +1508,9 @@ interface CompleteAuthorizationOptions {
|
|
|
1279
1508
|
*/
|
|
1280
1509
|
request: AuthRequest;
|
|
1281
1510
|
/**
|
|
1282
|
-
* Identifier for the user granting the authorization
|
|
1511
|
+
* Identifier for the user granting the authorization. Must be non-empty and must not contain
|
|
1512
|
+
* `:`, which separates the parts of issued tokens and storage keys; encode namespaced or
|
|
1513
|
+
* composite IDs first (for example `encodeURIComponent('tenant:user')`).
|
|
1283
1514
|
*/
|
|
1284
1515
|
userId: string;
|
|
1285
1516
|
/**
|
|
@@ -1302,15 +1533,6 @@ interface CompleteAuthorizationOptions {
|
|
|
1302
1533
|
* Set to false to allow multiple concurrent grants per user+client.
|
|
1303
1534
|
*/
|
|
1304
1535
|
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
1536
|
}
|
|
1315
1537
|
/**
|
|
1316
1538
|
* Authorization grant record
|
|
@@ -1467,7 +1689,8 @@ interface Token extends TokenBase {
|
|
|
1467
1689
|
*/
|
|
1468
1690
|
grant: {
|
|
1469
1691
|
/**
|
|
1470
|
-
* Client
|
|
1692
|
+
* Client this token was issued to: the grant's client, or, for a token from an allowed
|
|
1693
|
+
* cross-client token exchange, the client that requested it (RFC 8693).
|
|
1471
1694
|
*/
|
|
1472
1695
|
clientId: string;
|
|
1473
1696
|
/**
|
|
@@ -1490,7 +1713,8 @@ interface TokenSummary<T = any> extends TokenBase {
|
|
|
1490
1713
|
*/
|
|
1491
1714
|
grant: {
|
|
1492
1715
|
/**
|
|
1493
|
-
* Client
|
|
1716
|
+
* Client this token was issued to: the grant's client, or, for a token from an allowed
|
|
1717
|
+
* cross-client token exchange, the client that requested it (RFC 8693).
|
|
1494
1718
|
*/
|
|
1495
1719
|
clientId: string;
|
|
1496
1720
|
/**
|
|
@@ -1562,6 +1786,12 @@ interface PurgeOptions {
|
|
|
1562
1786
|
* Defaults to true.
|
|
1563
1787
|
*/
|
|
1564
1788
|
purgeOrphanedTokens?: boolean;
|
|
1789
|
+
/**
|
|
1790
|
+
* Where to resume: the `cursor` from the previous invocation's result. Omit it to start
|
|
1791
|
+
* a new sweep. Persist the returned cursor between invocations (for example in KV), or
|
|
1792
|
+
* every invocation re-checks the same first `batchSize` records.
|
|
1793
|
+
*/
|
|
1794
|
+
cursor?: string;
|
|
1565
1795
|
}
|
|
1566
1796
|
/**
|
|
1567
1797
|
* Result of a purgeExpiredData garbage collection invocation
|
|
@@ -1575,8 +1805,10 @@ interface PurgeResult {
|
|
|
1575
1805
|
tokensChecked: number;
|
|
1576
1806
|
/** Number of token records purged (orphaned) */
|
|
1577
1807
|
tokensPurged: number;
|
|
1578
|
-
/** True
|
|
1808
|
+
/** True once the sweep has covered both key spaces; there is no `cursor` then. */
|
|
1579
1809
|
done: boolean;
|
|
1810
|
+
/** Pass as `PurgeOptions.cursor` to the next invocation to continue this sweep. Absent when `done`. */
|
|
1811
|
+
cursor?: string;
|
|
1580
1812
|
}
|
|
1581
1813
|
/**
|
|
1582
1814
|
* Public representation of a grant, with sensitive data removed
|
|
@@ -1700,108 +1932,6 @@ declare function getOAuthApi<Env = Cloudflare.Env>(options: OAuthProviderOptions
|
|
|
1700
1932
|
* Error class for OAuth operations
|
|
1701
1933
|
* Carries OAuth error code and description for proper error responses
|
|
1702
1934
|
*/
|
|
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
1935
|
/** Options accepted by the {@link ExternalTokenError} constructor. */
|
|
1806
1936
|
interface ExternalTokenErrorOptions {
|
|
1807
1937
|
/**
|
|
@@ -1878,20 +2008,5 @@ declare class CimdFetchError extends Error {
|
|
|
1878
2008
|
*/
|
|
1879
2009
|
constructor(metadataUrl: string, cause: unknown);
|
|
1880
2010
|
}
|
|
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
2011
|
//#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,
|
|
2012
|
+
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 };
|