@cloudflare/workers-oauth-provider 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/oauth-provider.js +26 -4
- package/package.json +1 -1
package/dist/oauth-provider.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
2
2
|
|
|
3
3
|
//#region src/oauth-provider.ts
|
|
4
|
+
const PROTECTED_RESOURCE_WELL_KNOWN_PREFIX = "/.well-known/oauth-protected-resource";
|
|
4
5
|
if (!(typeof Cloudflare !== "undefined" && Cloudflare.compatibilityFlags?.global_fetch_strictly_public === true)) console.warn("CIMD (Client ID Metadata Document) is disabled: add '\"compatibility_flags\": [\"global_fetch_strictly_public\"]' to your wrangler.jsonc to enable. See: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#global-fetch-strictly-public");
|
|
5
6
|
/**
|
|
6
7
|
* Enum representing the type of handler (ExportedHandler or WorkerEntrypoint)
|
|
@@ -141,7 +142,7 @@ var OAuthProviderImpl = class OAuthProviderImpl {
|
|
|
141
142
|
async fetch(request, env, ctx) {
|
|
142
143
|
const url = new URL(request.url);
|
|
143
144
|
if (request.method === "OPTIONS") {
|
|
144
|
-
if (this.isApiRequest(url) || url.pathname === "/.well-known/oauth-authorization-server" || url
|
|
145
|
+
if (this.isApiRequest(url) || url.pathname === "/.well-known/oauth-authorization-server" || this.isProtectedResourceMetadataRequest(url) || this.isTokenEndpoint(url) || this.options.clientRegistrationEndpoint && this.isClientRegistrationEndpoint(url)) return this.addCorsHeaders(new Response(null, {
|
|
145
146
|
status: 204,
|
|
146
147
|
headers: { "Content-Length": "0" }
|
|
147
148
|
}), request);
|
|
@@ -150,7 +151,7 @@ var OAuthProviderImpl = class OAuthProviderImpl {
|
|
|
150
151
|
const response = await this.handleMetadataDiscovery(url);
|
|
151
152
|
return this.addCorsHeaders(response, request);
|
|
152
153
|
}
|
|
153
|
-
if (url
|
|
154
|
+
if (this.isProtectedResourceMetadataRequest(url)) {
|
|
154
155
|
const response = this.handleProtectedResourceMetadata(url);
|
|
155
156
|
return this.addCorsHeaders(response, request);
|
|
156
157
|
}
|
|
@@ -245,6 +246,27 @@ var OAuthProviderImpl = class OAuthProviderImpl {
|
|
|
245
246
|
return this.matchEndpoint(url, this.options.clientRegistrationEndpoint);
|
|
246
247
|
}
|
|
247
248
|
/**
|
|
249
|
+
* Checks if a URL is a request for OAuth Protected Resource Metadata (RFC 9728).
|
|
250
|
+
* Matches both the root well-known path and path-suffixed variants per RFC 9728 §3.1.
|
|
251
|
+
*/
|
|
252
|
+
isProtectedResourceMetadataRequest(url) {
|
|
253
|
+
return url.pathname === PROTECTED_RESOURCE_WELL_KNOWN_PREFIX || url.pathname.startsWith(PROTECTED_RESOURCE_WELL_KNOWN_PREFIX + "/");
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Derives the resource identifier from a protected resource metadata well-known URL.
|
|
257
|
+
* Per RFC 9728 §3.1, the well-known URI is inserted after the authority and before the path,
|
|
258
|
+
* so the resource identifier is reconstructed by removing the well-known prefix.
|
|
259
|
+
*
|
|
260
|
+
* Examples:
|
|
261
|
+
* /.well-known/oauth-protected-resource → origin (e.g. https://example.com)
|
|
262
|
+
* /.well-known/oauth-protected-resource/mcp → origin + /mcp (e.g. https://example.com/mcp)
|
|
263
|
+
*/
|
|
264
|
+
deriveResourceIdentifier(requestUrl) {
|
|
265
|
+
const suffix = requestUrl.pathname.slice(37);
|
|
266
|
+
if (!suffix || suffix === "/") return requestUrl.origin;
|
|
267
|
+
return `${requestUrl.origin}${suffix}`;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
248
270
|
* Parses and validates a token endpoint request (used for both token exchange and revocation)
|
|
249
271
|
* @param request - The HTTP request to parse
|
|
250
272
|
* @returns Promise with parsed body and client info, or error response
|
|
@@ -389,7 +411,7 @@ var OAuthProviderImpl = class OAuthProviderImpl {
|
|
|
389
411
|
const tokenEndpointUrl = this.getFullEndpointUrl(this.options.tokenEndpoint, requestUrl);
|
|
390
412
|
const authServerOrigin = new URL(tokenEndpointUrl).origin;
|
|
391
413
|
const metadata = {
|
|
392
|
-
resource: rm?.resource ?? requestUrl
|
|
414
|
+
resource: rm?.resource ?? this.deriveResourceIdentifier(requestUrl),
|
|
393
415
|
authorization_servers: rm?.authorization_servers ?? [authServerOrigin],
|
|
394
416
|
scopes_supported: rm?.scopes_supported ?? this.options.scopesSupported,
|
|
395
417
|
bearer_methods_supported: rm?.bearer_methods_supported ?? ["header"]
|
|
@@ -956,7 +978,7 @@ var OAuthProviderImpl = class OAuthProviderImpl {
|
|
|
956
978
|
*/
|
|
957
979
|
async handleApiRequest(request, env, ctx) {
|
|
958
980
|
const url = new URL(request.url);
|
|
959
|
-
const resourceMetadataUrl = `${url.origin}/.well-known/oauth-protected-resource`;
|
|
981
|
+
const resourceMetadataUrl = `${url.origin}/.well-known/oauth-protected-resource${url.pathname}`;
|
|
960
982
|
const authHeader = request.headers.get("Authorization");
|
|
961
983
|
if (!authHeader || !authHeader.startsWith("Bearer ")) return this.createErrorResponse("invalid_token", "Missing or invalid access token", 401, { "WWW-Authenticate": this.buildWwwAuthenticateHeader(resourceMetadataUrl, "invalid_token", "Missing or invalid access token") });
|
|
962
984
|
const accessToken = authHeader.substring(7);
|