
Cloudflare OAuth now supports scope customization, letting developers mark scopes as optional and users grant only the access they need. This shifts the consent experience from all-or-nothing to task-based, giving security-conscious users more control.
The All-or-Nothing Consent Problem
OAuth provides a standardized mechanism for delegated access, allowing applications to interact with resources on a user’s behalf without requiring long-lived credentials. However, the traditional “all-or-nothing” consent model frequently creates friction in complex environments, particularly for applications like Model Context Protocol (MCP) servers. These agents may define broad scope requirements to accommodate various potential tasks, creating a scenario where a user must either grant excessive privileges or deny access entirely. Before recent improvements, developers were forced to architect custom scope-selection interfaces prior to the OAuth redirect to mitigate this binary choice.
Since June, the growth of the Cloudflare OAuth ecosystem—spanning thousands of third-party applications and over a million authorizations—has necessitated a transition toward more granular permission models. Implementing optional scopes addresses this by allowing developers to designate specific scopes as non-mandatory during client configuration. This leverages the inherent flexibility of the OAuth specification, which permits authorization servers to grant a subset of requested scopes.
Key architectural considerations for implementing this feature include:
- Scope Categorization: Developers define scopes as either required or optional during the OAuth client registration phase.
- Request-Level Evaluation: Required and optional scopes are evaluated strictly against the scopes requested in a specific authorization flow. If an optional scope is not included in the initial request, it is excluded from the consent screen entirely.
- Dynamic Consent: During the authorization process, users may deselect optional scopes, resulting in an access token scoped only to the subset of approved permissions.
To implement optional scopes, define the optional_scopes field within the client configuration via the API:
{
"client_name": "ACME Corp",
"scopes": ["user-details.read", "workers-scripts.write", "workers-kv-storage.write", "zone.read"],
"optional_scopes": ["workers-kv-storage.write", "zone.read"]
}
Engineers must design applications to handle partial grants gracefully. Upon exchanging the authorization code, the application should programmatically inspect the granted scope set in the response rather than assuming the full requested set was provisioned. This approach enables a Principle of Least Privilege (PoLP) design, ensuring agents operate only with the specific permissions authorized by the user.
Introducing OAuth Scope Customization
OAuth lets applications act on a user's behalf without long-lived credentials or password sharing. The model works well when an application can describe its access needs with a small set of scopes. As permission models become more granular, an all-or-nothing consent screen becomes hard to justify: if an application requests more access than a user is comfortable granting, the only options are to approve the full request or deny outright.
The OAuth specification allows authorization servers to grant a narrower set of scopes than requested. Cloudflare's OAuth scope customization builds on that flexibility. Client owners can mark specific scopes as optional when configuring an OAuth client. At authorization time, users can deselect optional scopes, granting only the subset they are comfortable with. By default, the consent screen grants the full requested scope set. If no optional scopes are requested, the consent experience remains unchanged, and existing clients keep their current behavior.
Required and optional scopes are evaluated only against the scopes requested in a specific authorization flow, not every scope configured on the client. For example, a client might be configured with user-details.read, workers-scripts.write, workers-kv-storage.write, and zone.read, with the last two marked optional. If that client requests all four scopes, the user can deselect the optional ones. If it requests only workers-scripts.write and zone.read, only those two are considered for that flow.
Developers configure this by specifying optional scopes alongside the existing scope list:
"scopes": ["user-details.read", "workers-scripts.write", "workers-kv-storage.write", "zone.read"],
"optional_scopes": ["workers-kv-storage.write", "zone.read"]
When a user deselects optional scopes, the access token contains only the scopes they consented to. Developers should check the granted scope set after exchanging the authorization code rather than assuming the full requested set was approved.
- Request only the permissions your application needs; mark anything beyond that as optional.
- Handle a narrower grant gracefully; an agent should operate within whatever subset of permissions it receives.
- Treat the granted scope set as the source of truth after the authorization code exchange.
Scopes Are Evaluated Per Authorization Request
In OAuth 2.0, the authorization server evaluates scopes per authorization request, not against the full set configured on the client. When a client starts an authorization flow, only the scopes included in that specific request are candidates for consent and enforcement. The OAuth specification already permits authorization servers to grant a narrower set of scopes than what was requested, and this per-request evaluation builds on that flexibility. It also keeps the consent screen focused on the task at hand rather than every capability the application could request.
For example, a client might be configured with user-details.read, workers-scripts.write, workers-kv-storage.write, and zone.read, with workers-kv-storage.write and zone.read marked optional. If that client requests all four scopes, the consent screen evaluates all four: user-details.read and workers-scripts.write remain required, while the user can choose whether to grant the two optional scopes.
If the client later requests only workers-scripts.write and zone.read, only those two scopes are considered for that flow. user-details.read and workers-kv-storage.write would not be shown or enforced because they were not requested. Existing clients that do not opt into optional scopes keep their current consent behavior by default.
Key implications:
- Optional scopes become selectable only when included in the authorization request.
- Required scopes included in the request cannot be deselected; scopes absent from the request are never evaluated for that flow.
- If a user deselects optional scopes, the generated access token contains only the scopes the user approved.
- By default, the consent screen grants the full requested scope set.
After exchanging the authorization code, inspect the granted scope set on the token rather than assuming the full requested set was approved. Build the application to operate within whatever subset of permissions it receives. Request only the permissions needed for the current operation and mark the rest optional — this signals to users that the application respects their access decisions.
Configuring Optional Scopes on an OAuth Client
In traditional OAuth consent, a user must either approve the full set of scopes an application requests or deny the entire authorization. Scope customization changes this model by allowing client owners to designate a subset of their configured scopes as optional. At authorization time, the user can deselect those optional scopes on the consent screen while required scopes stay fixed. By default, the consent screen still grants the full requested scope set, so existing OAuth clients that do not opt into optimal scopes experience no behavioral change.
A critical nuance is that required and optional scopes are evaluated only against the scopes requested in a given authorization flow, never against every scope configured on the client. Consider a client configured with the following scopes:
user-details.readworkers-scripts.writeworkers-kv-storage.writezone.read
If workers-kv-storage.write and zone.read are marked optional and the client starts an authorization flow requesting all four scopes, the consent screen evaluates all four: user-details.read and workers-scripts.write remain required, while the user may narrow the two optional scopes. If the client later requests only workers-scripts.write and zone.read, then only those two scopes are considered in that flow. The unrequested scopes are neither shown nor enforced, keeping the consent screen focused on the task at hand.
To configure optional scopes on an OAuth client, include both arrays in the client configuration request:
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/oauth_clients" \
--request POST \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"client_name": "ACME Corp",
"redirect_uris": ["https://acme.org/oauth/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_basic",
"scopes": ["user-details.read", "workers-scripts.write", "workers-kv-storage.write", "zone.read"],
"optional_scopes": ["workers-kv-storage.write", "zone.read"]
}'
In this example, the client may request all four scopes, but the user can only opt out of workers-kv-storage.write and zone.read during consent. user-details.read and workers-scripts.write remain required when included in the authorization request.
When a user deselects optional scopes, the issued access token contains only the scopes the user consented to. Your application must therefore inspect the granted scope set after exchanging the authorization code rather than assuming the full requested set was approved. To build a resilient integration, request only the permissions your app truly needs, mark the rest as optional, and handle a narrower grant gracefully for security-conscious users.
Building with Partial Grants in Mind
The OAuth 2.0 framework permits an authorization server to grant a narrower set of scopes than the client requested. With optional scope selection, this becomes a user-visible decision: the consent screen presents the requested set, and the user may deselect any scopes the client owner marked as optional. Required and optional scopes are evaluated against the scopes in that specific authorization request, not against every scope configured on the client. For example, a client configured with user-details.read, workers-scripts.write, workers-kv-storage.write, and zone.read—with the last two marked optional—shows all four when requested together. If the same client later requests only workers-scripts.write and zone.read, those two alone are subject to user narrowing.
The consequence for developers: after exchanging the authorization code, the granted scope set may be narrower than requested. The token response includes the scopes actually consented to, so parse that value rather than assuming the full requested set was approved. The granted set should be stored with the token and checked before each downstream API call.
Recommended handling:
- Parse the granted
scopefrom the token response and persist it with the session. - Before an API call, confirm the operation's required scope is present in the granted set.
- If it is absent, degrade gracefully: hide the feature, return a clear error, or prompt re-authorization with a broader request.
An agent is a practical example: if it requests workers-scripts.write and workers-kv-storage.write but the user grants only the former, the agent should expose script management and decline KV operations, rather than failing on the first unauthorized call.
Finally, request only the scopes the application actually needs, and mark the rest as optional. This keeps the consent screen focused on the task at hand and signals that the application respects access decisions. For clients that do not opt into optional scopes, the consent experience remains unchanged—but for those that do, a partial grant must be treated as a normal runtime state, not an error path.
What's Next and How to Get Started
As the Cloudflare API ecosystem evolves, the authorization surface area is expanding to provide more granular control over workloads. Over the coming weeks, Cloudflare will extend account- and zone-level roles to encompass nearly every product in the portfolio. This expansion will introduce new API token roles, additional account membership configurations, and expanded OAuth scopes. For engineering teams, this transition facilitates the implementation of the principle of least privilege, ensuring that automated systems, agents, and SaaS integrations hold only the permissions strictly necessary for their function.
A central component of this shift is the implementation of optional OAuth scopes. By allowing developers to designate specific scopes as optional during client configuration, the system enables users to consent to a subset of requested permissions. This mechanism addresses the limitations of "all-or-nothing" consent models, which can inadvertently force over-privileged access.
Implementing Optional Scopes
When developing applications that interact with the Cloudflare API, engineers should adopt a defensive approach to scope handling. Developers must evaluate the granted scopes returned upon exchanging the authorization code, rather than assuming the full requested set was approved. Applications should be designed to degrade gracefully if certain optional permissions are withheld by the user.
To configure an OAuth client with optional scopes, define both required and optional parameters during the client creation request:
- Required Scopes: Essential permissions that remain mandatory for the application’s core functionality.
- Optional Scopes: Permissions that users may choose to exclude during the authorization flow.
For practical implementation, refer to the following resources:
- Review the Third Party OAuth documentation for detailed integration patterns.
- Access the OAuth apps page within the Cloudflare dashboard to begin configuring your client credentials.
This initiative represents a significant enhancement to the platform's security posture, driven in part by the high-impact contributions of interns Miller Vargas and José Enrique Rodriguez, both of whom played key roles in this release as part of Cloudflare’s 1,111-intern cohort.
Editorial Policy & Research Methodology
Our findings are based on rigorous internal research, verified industry benchmarks, and direct technical implementation experience from our enterprise client projects. All statistics and technical claims are reviewed by senior engineers before publication to ensure accuracy, transparency, and helpfulness for our readers.
