@cloudflare/workers-oauth-provider 0.10.2 → 0.10.4

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 CHANGED
@@ -248,6 +248,8 @@ A typical flow has three steps:
248
248
 
249
249
  `completeAuthorization()` stores a new grant and, by default, revokes existing grants for the same user and client after the new grant is safely stored. Set `revokeExistingGrants: false` only when the application intentionally allows concurrent grants for the same user and client.
250
250
 
251
+ 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
+
251
253
  For users with many grants, `revokeExistingGrantsBatchSize` controls the KV page size used during that scan. It defaults to `50` and is capped at KV's maximum page size of `1000`.
252
254
 
253
255
  ### Authorization response issuer
@@ -1103,6 +1103,13 @@ interface Grant {
1103
1103
  * Indicates the protected resource(s) for which access is requested
1104
1104
  */
1105
1105
  resource?: string | string[];
1106
+ /**
1107
+ * The exact redirect URI used in the authorization request that created this grant
1108
+ * Recorded so that default grant revocation can be scoped to a single installation
1109
+ * of a CIMD client (whose client_id is shared across all installations). Absent on
1110
+ * grants created before this field was introduced.
1111
+ */
1112
+ redirectUri?: string;
1106
1113
  }
1107
1114
  /**
1108
1115
  * OAuth 2.0 Token Response
@@ -1314,6 +1321,13 @@ interface GrantSummary {
1314
1321
  * Unix timestamp when the grant expires (if TTL is configured)
1315
1322
  */
1316
1323
  expiresAt?: number;
1324
+ /**
1325
+ * The exact redirect URI used in the authorization request that created this grant
1326
+ * Recorded so that default grant revocation can be scoped to a single installation
1327
+ * of a CIMD client (whose client_id is shared across all installations). Absent on
1328
+ * grants created before this field was introduced.
1329
+ */
1330
+ redirectUri?: string;
1317
1331
  }
1318
1332
  /**
1319
1333
  * OAuth 2.0 Provider implementation for Cloudflare Workers
@@ -581,6 +581,8 @@ const EMA_DEFAULT_MAX_ASSERTION_LIFETIME_SECONDS = 300;
581
581
  * values to amplify load on the IdP's JWKS endpoint.
582
582
  */
583
583
  const EMA_JWKS_FORCE_REFRESH_COOLDOWN_SECONDS = 30;
584
+ /** Floor for the `jti` replay marker's KV TTL; KV rejects a sub-60s expiration. */
585
+ const EMA_JTI_MIN_TTL_SECONDS = 60;
584
586
  /** Default JWT signing algorithm assumed for a trusted issuer. */
585
587
  const EMA_DEFAULT_JWT_ALGORITHM = "RS256";
586
588
  /** JWT signing algorithms supported by the built-in WebCrypto verifier. */
@@ -698,7 +700,7 @@ const EMA_JTI_KV_PREFIX = "enterprise-jti:";
698
700
  /** Create the default KV-backed JTI store. KV TTL handles cleanup. */
699
701
  function createKvJtiStore() {
700
702
  return { async markUsed({ issuer, jti, exp, now, env }) {
701
- const ttl = Math.max(1, exp - now);
703
+ const ttl = Math.max(EMA_JTI_MIN_TTL_SECONDS, exp - now);
702
704
  const key = `${EMA_JTI_KV_PREFIX}${await sha256Hex(`${issuer}\n${jti}`)}`;
703
705
  if (await env.OAUTH_KV.get(key)) return err({
704
706
  reason: "replayed",
@@ -3572,6 +3574,7 @@ var OAuthHelpersImpl = class {
3572
3574
  validateAuthorizationPkce(this.provider.serverCapabilities, options.request, clientInfo);
3573
3575
  let grantsToRevoke = [];
3574
3576
  if (options.revokeExistingGrants !== false) {
3577
+ const isCimdClient = this.provider.isClientMetadataUrl(clientId);
3575
3578
  const batchSize = getRevokeExistingGrantsBatchSize(options.revokeExistingGrantsBatchSize);
3576
3579
  let cursor;
3577
3580
  do {
@@ -3579,7 +3582,7 @@ var OAuthHelpersImpl = class {
3579
3582
  cursor,
3580
3583
  limit: batchSize
3581
3584
  });
3582
- for (const grant of page.items) if (grant.clientId === clientId) grantsToRevoke.push(grant.id);
3585
+ for (const grant of page.items) if (grant.clientId === clientId && (!isCimdClient || grant.redirectUri === options.request.redirectUri)) grantsToRevoke.push(grant.id);
3583
3586
  cursor = page.cursor;
3584
3587
  } while (cursor);
3585
3588
  }
@@ -3603,7 +3606,8 @@ var OAuthHelpersImpl = class {
3603
3606
  metadata: options.metadata,
3604
3607
  encryptedProps: encryptedData,
3605
3608
  createdAt: now,
3606
- resource: effectiveResource
3609
+ resource: effectiveResource,
3610
+ redirectUri: options.request.redirectUri
3607
3611
  };
3608
3612
  const grantKey = `grant:${options.userId}:${grantId}`;
3609
3613
  await this.env.OAUTH_KV.put(grantKey, JSON.stringify(grant));
@@ -3653,7 +3657,8 @@ var OAuthHelpersImpl = class {
3653
3657
  authCodeWrappedKey,
3654
3658
  codeChallenge: options.request.codeChallenge,
3655
3659
  codeChallengeMethod: options.request.codeChallengeMethod,
3656
- resource: effectiveResource
3660
+ resource: effectiveResource,
3661
+ redirectUri: options.request.redirectUri
3657
3662
  };
3658
3663
  const grantKey = `grant:${options.userId}:${grantId}`;
3659
3664
  await this.env.OAUTH_KV.put(grantKey, JSON.stringify(grant), { expirationTtl: 600 });
@@ -3810,7 +3815,8 @@ var OAuthHelpersImpl = class {
3810
3815
  scope: grantData.scope,
3811
3816
  metadata: grantData.metadata,
3812
3817
  createdAt: grantData.createdAt,
3813
- expiresAt: grantData.expiresAt
3818
+ expiresAt: grantData.expiresAt,
3819
+ redirectUri: grantData.redirectUri
3814
3820
  };
3815
3821
  grantSummaries.push(summary);
3816
3822
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/workers-oauth-provider",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "description": "OAuth provider for Cloudflare Workers",
5
5
  "main": "dist/oauth-provider.js",
6
6
  "types": "dist/oauth-provider.d.ts",