@cloudflare/workers-oauth-provider 0.10.4 → 1.0.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 +144 -50
- package/dist/oauth-provider.d.ts +334 -89
- package/dist/oauth-provider.js +1393 -309
- package/docs/advanced-configuration.md +370 -0
- package/docs/migration-1.0.md +97 -0
- package/docs/resource-servers.md +153 -0
- package/package.json +4 -2
- package/skills/migrate-to-1.0/SKILL.md +35 -0
package/README.md
CHANGED
|
@@ -148,10 +148,60 @@ export default new OAuthProvider<Env>({
|
|
|
148
148
|
|
|
149
149
|
`apiRoute` and `apiHandler` protect one or more route prefixes with a single handler. Use `apiHandlers` when different prefixes need different handlers.
|
|
150
150
|
|
|
151
|
-
Before calling a protected handler, the provider reads the bearer token, rejects missing, invalid, or expired credentials, checks its audience, and exposes the authenticated application data through `ctx.props
|
|
151
|
+
Before calling a protected handler, the provider reads the bearer token, rejects missing, invalid, or expired credentials, checks its audience, and exposes the authenticated application data through `ctx.props` and what it verified about the token through `ctx.auth` (`scope`, `userId`, `clientId`, `audience`, `expiresAt`). The handler does not need to parse or validate the token, but it still enforces application permissions such as scope, ownership, and tenancy; `insufficientScope(ctx.auth, scopes)` builds the MCP `403` challenge when a token lacks what an operation needs.
|
|
152
152
|
|
|
153
153
|
Requests outside the protected route prefixes go to `defaultHandler`. In the example above, that handler owns `/authorize`.
|
|
154
154
|
|
|
155
|
+
## One authorization server with multiple MCP resources
|
|
156
|
+
|
|
157
|
+
`OAuthAuthorizationServer` is the authorization-server role on its own: discovery, token, revocation and registration endpoints from `fetch()`, the interactive flow through `getOAuthApi()`, and `validateToken(resource, token, env)` for any resource in its fixed `resources` registry. Each resource is hosted by `new OAuthResourceServer()`, whose `validateToken` option points back at the authorization server — in this Worker or another. Same host, same `ctx.props`, wherever the resource runs.
|
|
158
|
+
|
|
159
|
+
**Same Worker.** Route the authorization server's origin to `authorizationServer.fetch()`, your `/authorize` page to `getOAuthApi()`, and each resource to its host. The validator is a direct call:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const authorizationServer = new OAuthAuthorizationServer<Env>({
|
|
163
|
+
issuer: 'https://auth.example.com',
|
|
164
|
+
resources: ['https://calendar.example.com/mcp'],
|
|
165
|
+
authorizeEndpoint: '/authorize',
|
|
166
|
+
tokenEndpoint: '/oauth/token',
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const calendar = new OAuthResourceServer<Env, AuthProps>({
|
|
170
|
+
resourceMetadata: {
|
|
171
|
+
resource: 'https://calendar.example.com/mcp',
|
|
172
|
+
authorization_servers: ['https://auth.example.com'],
|
|
173
|
+
},
|
|
174
|
+
validateToken: (env) => (resource, token) => authorizationServer.validateToken(resource, token, env),
|
|
175
|
+
handler: { fetch: (_request, _env, ctx) => Response.json({ userId: ctx.props.userId }) },
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Separate Workers.** The authorization Worker exposes `validateToken` from a `WorkerEntrypoint`; the resource Worker holds a Service Binding to it and hands the host that method. Nothing else to configure, and the validator is a binding, not a URL — it is not reachable from the public internet:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
// auth Worker
|
|
183
|
+
export default class AuthServer extends WorkerEntrypoint<Env> {
|
|
184
|
+
fetch(request: Request) {
|
|
185
|
+
return authorizationServer.fetch(request, this.env, this.ctx);
|
|
186
|
+
}
|
|
187
|
+
validateToken(resource: string, token: string) {
|
|
188
|
+
return authorizationServer.validateToken(resource, token, this.env);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// calendar Worker, with `"services": [{ "binding": "AUTH_SERVER", "service": "auth" }]` in wrangler.jsonc
|
|
193
|
+
export default new OAuthResourceServer<Env, AuthProps>({
|
|
194
|
+
resourceMetadata: {
|
|
195
|
+
resource: 'https://calendar.example.com/mcp',
|
|
196
|
+
authorization_servers: ['https://auth.example.com'],
|
|
197
|
+
},
|
|
198
|
+
validateToken: (env) => env.AUTH_SERVER.validateToken,
|
|
199
|
+
handler,
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Either way the resource server publishes its own RFC 9728 metadata, issues Bearer challenges that point at it, checks the returned audience against its canonical resource, and answers `503` when validation infrastructure fails. Tokens are opaque throughout; a validator returns the decrypted `props` the authorization flow stored. See [docs/resource-servers.md](docs/resource-servers.md) for the three-domain Hono example, the `AuthorizationServerBinding` type for your `Env`, and how to validate tokens from another issuer at your own risk.
|
|
204
|
+
|
|
155
205
|
## How MCP authorization discovery works
|
|
156
206
|
|
|
157
207
|
An MCP client discovers authorization in two stages, following the [MCP authorization server discovery rules](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/authorization-server-discovery).
|
|
@@ -162,7 +212,7 @@ For an MCP endpoint at `https://mcp.example.com/mcp`:
|
|
|
162
212
|
2. The provider returns `401 Unauthorized` with a challenge similar to:
|
|
163
213
|
|
|
164
214
|
```http
|
|
165
|
-
WWW-Authenticate: Bearer realm="OAuth", resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp"
|
|
215
|
+
WWW-Authenticate: Bearer realm="OAuth", resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp", scope="mcp:read"
|
|
166
216
|
```
|
|
167
217
|
|
|
168
218
|
3. The client fetches the protected resource metadata:
|
|
@@ -172,7 +222,7 @@ For an MCP endpoint at `https://mcp.example.com/mcp`:
|
|
|
172
222
|
```
|
|
173
223
|
|
|
174
224
|
4. That document identifies one or more authorization server issuers through `authorization_servers`.
|
|
175
|
-
5. The client fetches
|
|
225
|
+
5. The client fetches RFC 8414 authorization server metadata from the selected issuer. In the single-origin quick start that is:
|
|
176
226
|
|
|
177
227
|
```text
|
|
178
228
|
https://mcp.example.com/.well-known/oauth-authorization-server
|
|
@@ -187,21 +237,7 @@ Protected resource metadata and authorization server metadata serve different ro
|
|
|
187
237
|
|
|
188
238
|
### Protected resource metadata
|
|
189
239
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
```text
|
|
193
|
-
/.well-known/oauth-protected-resource
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
It also supports path-specific metadata. A request to:
|
|
197
|
-
|
|
198
|
-
```text
|
|
199
|
-
/.well-known/oauth-protected-resource/public/mcp
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
produces `https://example.com/public/mcp` as the derived resource unless `resourceMetadata.resource` overrides it.
|
|
203
|
-
|
|
204
|
-
For MCP deployments, configure the canonical MCP endpoint explicitly:
|
|
240
|
+
Every protected resource needs its own `resourceMetadata.resource`. Configure each canonical HTTPS identifier with a lowercase scheme and host (plain `http` is accepted only on a loopback host, for `wrangler dev`):
|
|
205
241
|
|
|
206
242
|
```ts
|
|
207
243
|
resourceMetadata: {
|
|
@@ -213,7 +249,17 @@ resourceMetadata: {
|
|
|
213
249
|
}
|
|
214
250
|
```
|
|
215
251
|
|
|
216
|
-
|
|
252
|
+
For the example above, an unauthenticated request to the exact canonical URL receives a Bearer challenge pointing to:
|
|
253
|
+
|
|
254
|
+
```text
|
|
255
|
+
https://mcp.example.com/.well-known/oauth-protected-resource/mcp
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
That document returns the configured canonical `resource`. The discovery URL is built from the canonical resource: an origin uses `/.well-known/oauth-protected-resource`, and a path and query are inserted after the well-known prefix.
|
|
259
|
+
|
|
260
|
+
A canonical path is the base audience for its path-boundary descendants: a token for `https://mcp.example.com/mcp` is accepted at `/mcp/tools`, and a challenge at `/mcp/tools` advertises the one canonical document for `/mcp`, as RFC 9728 §5.1 permits. A request on another origin, or one that the canonical resource does not cover, gets a challenge without `resource_metadata`. Every protected route must be the canonical resource path or a descendant of it; the provider rejects any other `apiRoute` or `apiHandlers` key at construction, because a token could never validate there.
|
|
261
|
+
|
|
262
|
+
`authorization_servers` may contain more than one issuer. Each value must use canonical HTTPS issuer spelling: lowercase scheme and host, with no userinfo, default port, dot segments, query, or fragment. As with resources, `http` is accepted only on a loopback host. OAuth issuer comparison is exact. The MCP client chooses an authorization server and must keep credentials and tokens separate for each issuer. `new OAuthResourceServer()` requires it explicitly, wherever the resource runs.
|
|
217
263
|
|
|
218
264
|
### Authorization server metadata
|
|
219
265
|
|
|
@@ -222,6 +268,7 @@ The provider publishes RFC 8414 metadata containing:
|
|
|
222
268
|
- `issuer`
|
|
223
269
|
- `authorization_endpoint`
|
|
224
270
|
- `token_endpoint`
|
|
271
|
+
- `protected_resources`, containing the authorization server's registered canonical resources
|
|
225
272
|
- `registration_endpoint`, when DCR is enabled
|
|
226
273
|
- supported response and grant types
|
|
227
274
|
- token endpoint authentication methods
|
|
@@ -246,7 +293,7 @@ A typical flow has three steps:
|
|
|
246
293
|
|
|
247
294
|
`completeAuthorization()` repeats response-type validation before writing a grant or revoking existing grants. Validation errors from reconstructed requests are also typed as `AuthorizationError`, but applications should not construct redirects from untrusted reconstructed values; the redirect context is attached only by `parseAuthRequest()`.
|
|
248
295
|
|
|
249
|
-
`completeAuthorization()` stores a new grant and, by default, revokes existing grants for the same user and
|
|
296
|
+
`completeAuthorization()` stores a new grant and, by default, revokes existing grants for the same user, client, and resource after the new grant is safely stored. A grant for another registered resource is a separate authorization and is not revoked. Set `revokeExistingGrants: false` only when the application intentionally allows concurrent grants within the same resource.
|
|
250
297
|
|
|
251
298
|
For Client ID Metadata Document clients, whose client_id is the metadata URL shared by every installation, default revocation is additionally scoped to grants created from the same redirect URI, so one installation's re-authorization does not revoke another's. Grants created before the redirect URI was recorded are never auto-revoked by CIMD clients.
|
|
252
299
|
|
|
@@ -324,7 +371,7 @@ clientRegistrationEndpoint: '/oauth/register';
|
|
|
324
371
|
|
|
325
372
|
MCP 2026-07-28 deprecates DCR for new implementations in favor of CIMD. The endpoint remains useful for compatibility with clients that do not support CIMD.
|
|
326
373
|
|
|
327
|
-
Registration accepts only authentication methods, grants, and response types implemented by the configured provider, and rejects inconsistent grant/response combinations before storage. Choice-valued `token_endpoint_auth_methods_supported` input is negotiated to one effective `token_endpoint_auth_method`; grant and response registrations remain strict. Omitted metadata uses the RFC 7591 defaults: `client_secret_basic`, `grant_types: ["authorization_code"]`, and `response_types: ["code"]`.
|
|
374
|
+
Registration accepts only authentication methods, grants, and response types implemented by the configured provider, and rejects inconsistent grant/response combinations before storage. Choice-valued `token_endpoint_auth_methods_supported` input is negotiated to one effective `token_endpoint_auth_method`; grant and response registrations remain strict. Omitted metadata uses the RFC 7591 defaults: `client_secret_basic`, `grant_types: ["authorization_code"]`, and `response_types: ["code"]`. The token endpoint enforces each client's registered grant types with `unauthorized_client`; `refresh_token` is implied by `authorization_code`, and a client must register `urn:ietf:params:oauth:grant-type:token-exchange` to use token exchange.
|
|
328
375
|
|
|
329
376
|
The effective `token_endpoint_auth_method` returned by registration is enforced exactly. When both authentication metadata fields are omitted, no explicit-method marker is stored and the client may use either `client_secret_basic` or `client_secret_post`, provided the same stored secret validates. Client records written by earlier releases have no marker and receive the same compatibility. This never crosses between `none` and a secret method and does not apply to CIMD clients.
|
|
330
377
|
|
|
@@ -332,7 +379,7 @@ Calling `OAuthHelpers.updateClient()` with `tokenEndpointAuthMethod` adds the ma
|
|
|
332
379
|
|
|
333
380
|
Related options:
|
|
334
381
|
|
|
335
|
-
- `clientRegistrationTTL` controls the lifetime of dynamically registered clients. The default is 90 days.
|
|
382
|
+
- `clientRegistrationTTL` controls the lifetime of dynamically registered clients. The default is 90 days. A registration still in use does not expire: once it has passed half its lifetime, the next successful token request renews it for the full TTL, so a client that keeps refreshing keeps its `client_id` while an abandoned one is cleaned up. The `client_secret_expires_at` returned at registration describes the initial lifetime; there is no channel to report a renewal, so a client that honours it re-registers on that schedule as before.
|
|
336
383
|
- `disallowPublicClientRegistration` rejects DCR clients using `token_endpoint_auth_method: "none"`.
|
|
337
384
|
- `clientRegistrationCallback` can allow or reject registration based on application policy.
|
|
338
385
|
|
|
@@ -352,21 +399,53 @@ allowPlainPKCE: true;
|
|
|
352
399
|
|
|
353
400
|
The provider owns `tokenEndpoint`. It exchanges authorization codes for tokens, refreshes access tokens, and handles RFC 7009 revocation. Refresh tokens rotate on use. The immediately previous token remains valid until its replacement is first used, allowing a client to retry after losing a refresh response.
|
|
354
401
|
|
|
402
|
+
A grant expires `refreshTokenTTL` seconds after the code exchange (30 days by default) however often it is refreshed. Set `refreshTokenIdleTTL` to make that lifetime slide instead: each successful refresh moves the expiry to that many seconds later, so a grant lives while the client keeps using it and expires once idle. `tokenExchangeCallback` can return `refreshTokenIdleTTL` to set the lifetime for one refresh, which lets a Worker that proxies an upstream OAuth service match the lifetime of the upstream refresh token it just rotated. See [Advanced configuration](docs/advanced-configuration.md#token-and-client-lifetimes).
|
|
403
|
+
|
|
355
404
|
## Resources and token audiences
|
|
356
405
|
|
|
357
|
-
|
|
406
|
+
An authorization server may register one or more protected resources. Each resource has one canonical `resourceMetadata.resource`: an absolute HTTPS URI without a fragment, with lowercase `https` and a lowercase host, and an RFC 3986-safe producer serialization. Userinfo, default ports, dot-segment paths, and an empty path before a query are rejected because `Request` would rewrite them before RFC 9728 comparison. A bare origin is the only empty-path exception; use `/` before a query. Query components are supported but discouraged by RFC 9728.
|
|
407
|
+
|
|
408
|
+
For local development, `http` is accepted for resources, `authorization_servers`, the explicit `OAuthAuthorizationServer` issuer, and absolute endpoint URLs only when the host is a loopback address (`localhost`, `127.0.0.0/8`, `::1`), so `wrangler dev` works at `http://localhost:8787`. Any other host must use `https`: Workers are always served over `https`, and OAuth 2.1 requires it. A local MCP client's loopback redirect URI is unaffected by this rule; it is governed by the RFC 8252 loopback handling described under client registration.
|
|
358
409
|
|
|
359
|
-
|
|
410
|
+
Every authorization grant and access token is bound to exactly one registered resource. A central authorization server can therefore issue separate Calendar and Drive tokens from one KV namespace, but it never turns those into one multi-audience bearer token. Completing a new authorization for Drive does not replace the same user and client's Calendar grant.
|
|
360
411
|
|
|
361
|
-
`
|
|
412
|
+
Conforming MCP clients are required to send `resource` in authorization and token requests. Resource selection and compatibility work as follows:
|
|
413
|
+
|
|
414
|
+
- When the authorization server has one registered resource, that sole resource is selected if an authorization request omits `resource`. This preserves existing `OAuthProvider` behavior.
|
|
415
|
+
- When it has multiple registered resources, an authorization request must identify exactly one of them. Set `defaultResource` on `OAuthAuthorizationServer` only when older clients that omit `resource` should be routed to a deliberate compatibility default.
|
|
416
|
+
- An authorization-code or refresh-token request may omit `resource`; the server inherits the resource already stored on the grant. If present, it must match that grant and cannot retarget it.
|
|
417
|
+
- Malformed, unknown, or multi-valued resource input returns `invalid_target` before code consumption, callbacks, refresh rotation, or storage writes.
|
|
418
|
+
|
|
419
|
+
ASCII case differences in the URI scheme and host are accepted, but port, path, query, trailing slash, and array cardinality remain strict. The authorization server always stores and returns the configured lowercase scheme-and-host spelling. The token response includes the selected resource, and the access-token audience contains that resource alone.
|
|
420
|
+
|
|
421
|
+
Token exchange cannot change the resource. Both the subject-token audience and any explicit requested resource must resolve to the same registered canonical value. A token is exchanged by the client its grant was issued to unless `tokenExchangeCallback` returns `allowCrossClientExchange: true`. Internally and externally validated tokens are accepted at a protected route only when their audience matches that route's resource.
|
|
422
|
+
|
|
423
|
+
Path-aware API validation uses path-boundary prefix matching. A canonical audience for `https://example.com/mcp` covers `/mcp` and `/mcp/tools`, but not `/mcp-other`. A canonical trailing slash remains significant.
|
|
424
|
+
|
|
425
|
+
### Upgrading to 1.0
|
|
426
|
+
|
|
427
|
+
The step-by-step guide, including an "Am I affected" checklist and an agent skill (`skills/migrate-to-1.0/`), is [docs/migration-1.0.md](docs/migration-1.0.md). The compatibility rules it relies on:
|
|
428
|
+
|
|
429
|
+
The existing combined `OAuthProvider` configuration has one `resourceMetadata.resource`. That sole resource automatically acts as both the omitted-authorization default and the migration destination for grants created before resource binding, so existing single-resource clients can continue without adding a `resource` parameter.
|
|
430
|
+
|
|
431
|
+
For a multi-resource `OAuthAuthorizationServer`, `defaultResource` and `legacyGrantResource` solve different compatibility problems:
|
|
432
|
+
|
|
433
|
+
- `defaultResource` selects the resource for a new authorization request that omits `resource`.
|
|
434
|
+
- `legacyGrantResource` is the server-controlled migration destination for an old stored grant or access token that has no resource. A client-supplied token-request parameter cannot choose or change this destination. It is deployment policy rather than an issuance-time claim, so changing it re-targets every surviving unbound record; keep it fixed for the migration window.
|
|
435
|
+
|
|
436
|
+
Both values must name a declared resource and are checked at construction. If a multi-resource server omits `legacyGrantResource`, an old unbound grant cannot be migrated safely. A stored grant already bound to a registered resource keeps that resource, and a stored 0.x array that contains the registered resource resolves to it. A grant bound only to unregistered values fails its refresh with `invalid_grant`, which conformant clients answer by starting a new authorization.
|
|
437
|
+
|
|
438
|
+
Previously issued access tokens with no audience keep working until they expire. They are treated as bound to the server-selected migration resource (the sole resource, or `legacyGrantResource`), and refresh binds the grant and returns a bound replacement token. A multi-resource server without `legacyGrantResource` has no safe destination, so it rejects such tokens and their refresh grants must be reauthorized. Multiple resources can share the same authorization server, provider implementation, and KV namespace; separate storage is an optional deployment boundary, not a resource-binding requirement.
|
|
439
|
+
|
|
440
|
+
The 1.0 API removes `resourceMatchOriginOnly`, and a configuration that still sets it fails at construction. Canonical matching with scheme/host case tolerance replaces it.
|
|
362
441
|
|
|
363
442
|
## Scopes and step-up authorization
|
|
364
443
|
|
|
365
|
-
`scopesSupported` is published only in authorization server metadata. Configure `resourceMetadata.scopes_supported` explicitly with the minimal scopes required for basic
|
|
444
|
+
`scopesSupported` is published only in authorization server metadata. Configure each protected resource's `resourceMetadata.scopes_supported` explicitly with the minimal scopes required for its basic functionality and baseline Bearer challenges.
|
|
366
445
|
|
|
367
446
|
The application decides which requested scopes to grant through `completeAuthorization({ scope })`. Token and refresh requests can only narrow those scopes.
|
|
368
447
|
|
|
369
|
-
|
|
448
|
+
Both hosts name `scopes_supported` in the initial `401` challenge, so a client asks for the right scopes first time. Operation-level policy stays in the handler, which reads the token's scopes from `ctx.auth.scope` and answers a shortfall with `insufficientScope(ctx.auth, ['files:write'])`: `403`, `error="insufficient_scope"`, every scope the operation needs in one challenge, and the resource's metadata URL. See [docs/resource-servers.md](docs/resource-servers.md#what-the-handler-sees).
|
|
370
449
|
|
|
371
450
|
## Advanced features
|
|
372
451
|
|
|
@@ -378,6 +457,7 @@ The package also supports:
|
|
|
378
457
|
- Structured callback errors through the exported `OAuthError` and `ExternalTokenError` classes.
|
|
379
458
|
- Custom error observation or responses through `onError`.
|
|
380
459
|
- Experimental MCP Enterprise-Managed Authorization using ID-JAG assertions.
|
|
460
|
+
- One authorization server with multiple same-Worker or separately routed MCP resources.
|
|
381
461
|
- Multiple protected handlers through `apiHandlers`.
|
|
382
462
|
- Configurable access token, refresh token, and DCR client lifetimes.
|
|
383
463
|
|
|
@@ -393,6 +473,8 @@ Sensitive values are not stored in plaintext:
|
|
|
393
473
|
|
|
394
474
|
See [storage-schema.md](https://github.com/cloudflare/workers-oauth-provider/blob/main/storage-schema.md) for the complete KV layout.
|
|
395
475
|
|
|
476
|
+
By default `completeAuthorization()` revokes the user's earlier grants for the same client and resource. It finds them from KV key metadata that every grant written by 1.0 or later carries, so the cost is one `list()` per thousand grants the user has, not a read per grant. Grants written before 1.0 are read individually, `revokeExistingGrantsBatchSize` at a time (default 50), until a refresh rewrites them with metadata.
|
|
477
|
+
|
|
396
478
|
KV TTLs remove expiring records automatically. `purgeExpiredData()` provides a manual sweep for orphaned or expired grants and tokens:
|
|
397
479
|
|
|
398
480
|
```ts
|
|
@@ -417,29 +499,41 @@ Deleting a client through `OAuthHelpers.deleteClient()` also revokes its grants
|
|
|
417
499
|
|
|
418
500
|
## Configuration reference
|
|
419
501
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
|
423
|
-
|
|
|
424
|
-
| `
|
|
425
|
-
| `
|
|
426
|
-
| `
|
|
427
|
-
| `
|
|
428
|
-
| `
|
|
429
|
-
| `
|
|
430
|
-
| `
|
|
431
|
-
| `
|
|
432
|
-
| `
|
|
433
|
-
| `
|
|
434
|
-
| `
|
|
435
|
-
| `
|
|
436
|
-
| `
|
|
437
|
-
| `
|
|
438
|
-
| `
|
|
439
|
-
| `
|
|
440
|
-
| `
|
|
441
|
-
|
|
442
|
-
|
|
502
|
+
The existing `OAuthProvider` combined configuration uses these options:
|
|
503
|
+
|
|
504
|
+
| Option | Purpose | Default |
|
|
505
|
+
| ---------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------- |
|
|
506
|
+
| `apiRoute` and `apiHandler` | Protect one or more route prefixes with one handler | Use these or `apiHandlers` |
|
|
507
|
+
| `apiHandlers` | Map protected route prefixes to different handlers | Use this or `apiRoute` plus `apiHandler` |
|
|
508
|
+
| `defaultHandler` | Handle authorization UI and other unprotected routes | Required |
|
|
509
|
+
| `authorizeEndpoint` | Application-owned authorization and consent endpoint | Required |
|
|
510
|
+
| `tokenEndpoint` | Provider-owned token and revocation endpoint | Required |
|
|
511
|
+
| `clientRegistrationEndpoint` | Enable RFC 7591 DCR | Disabled |
|
|
512
|
+
| `scopesSupported` | Publish authorization server scopes | Omitted |
|
|
513
|
+
| `resourceMetadata.resource` | Canonical HTTPS resource and token audience | Required |
|
|
514
|
+
| `clientIdMetadataDocumentEnabled` | Enable CIMD lookup and advertisement | `false` |
|
|
515
|
+
| `allowPlainPKCE` | Permit the legacy plain PKCE method | `false` |
|
|
516
|
+
| `allowImplicitFlow` | Enable implicit token responses | `false` |
|
|
517
|
+
| `disallowPublicClientRegistration` | Reject public clients at DCR | `false` |
|
|
518
|
+
| `clientRegistrationCallback` | Apply application policy before storing a DCR client | None |
|
|
519
|
+
| `allowTokenExchangeGrant` | Enable RFC 8693 | `false` |
|
|
520
|
+
| `tokenExchangeCallback` | Update props, scopes, or lifetimes during token exchange | None |
|
|
521
|
+
| `resolveExternalToken` | Validate external bearer credentials (advanced) | None |
|
|
522
|
+
| `enterpriseManagedAuthorization` | Enable experimental ID-JAG grant support | Disabled |
|
|
523
|
+
| `onError` | Observe or replace OAuth error responses; `internal` names the failed check | Logs a warning |
|
|
524
|
+
|
|
525
|
+
The functional role API adds these surfaces without removing `OAuthProvider`:
|
|
526
|
+
|
|
527
|
+
| Surface | Purpose |
|
|
528
|
+
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
529
|
+
| `new OAuthAuthorizationServer({ issuer, resources, … })` | Create the AS role with a canonical RFC 8414 issuer and its fixed resource registry |
|
|
530
|
+
| `validateToken(resource, token, env)` | Validate an access token for one declared resource; what a resource server calls |
|
|
531
|
+
| `defaultResource` | Select a deliberate default for new authorization requests that omit it |
|
|
532
|
+
| `legacyGrantResource` | Select the server-controlled migration target for old unbound grants |
|
|
533
|
+
| `getOAuthApi(env)` | Obtain OAuth helpers for an application-owned authorization route |
|
|
534
|
+
| `new OAuthResourceServer({ … })` | Host one resource, in this Worker or another; `validateToken` points at the AS or a binding |
|
|
535
|
+
|
|
536
|
+
Consult the exported `OAuthProviderOptions`, `OAuthAuthorizationServerOptions`, resource-server callback interfaces, and JSDoc in [`src/oauth-provider.ts`](https://github.com/cloudflare/workers-oauth-provider/blob/main/src/oauth-provider.ts) for the complete typed API.
|
|
443
537
|
|
|
444
538
|
## OAuth helpers
|
|
445
539
|
|