Scopes on Resources
API Resources use OAuth scopes tied to Role-Based Access Control (RBAC). MCP Server Resources use MCP OAuth scopes that can map to Connection scopes when tools need external credentials.
For how OAuth clients request these scopes, see Inbound Apps (APIs) and Agentic clients (MCP).
For controlling which clients can receive which scopes, see Policies.
API Resources
API Resources define the permission catalog for a protected API:
- Scopes — What a client may do on the API (
contacts.read,orders.write). These appear in the token'sscopeclaim and are what you typically enforce per route. - Roles — Descope RBAC roles mapped to each scope. Roles carry permissions your backend may already understand. When a scope is granted, the mapped role(s) can appear in the token's
rolesclaim so APIs can authorize from roles/permissions instead of maintaining a separate OAuth-scope map.
Permission scopes
| Field | Description |
|---|---|
| Name | Scope string in authorize/token requests and in the scope claim (e.g. shipments.read) |
| Description | Shown on consent screens when an Inbound App requests access |
| Roles | RBAC roles associated with this scope |
Define roles and permissions under Authorization → RBAC, or via Management SDKs. Assign roles to users in the users table, through SSO group mapping, or programmatically.
How scope ↔ role mapping works
On an API Resource, each permission scope can be linked to one or more Descope roles. That mapping does two related jobs:
- Eligibility (user-delegated flows) — A user can only consent to (and receive) a scope if they hold at least one of the roles mapped to that scope (or otherwise satisfy RBAC for it).
- Token claims — When a scope is granted on a Resource access token, Descope includes the roles mapped to that granted scope in the token's
rolesclaim (see User-delegated vs M2M below).
So if scope orders.write is mapped to role Order Editor, a token that includes orders.write can also include "roles": ["Order Editor"]. Your API can then resolve permissions under Order Editor the same way it does for first-party sessions, instead of hard-coding every OAuth scope in the backend.
| Claim | Meaning |
|---|---|
scope | Space-separated OAuth scopes granted for this Resource |
roles | Roles tied to those granted scopes (not necessarily every role the user or client has elsewhere) |
aud | Resource identifier (and any default audience values) |
{
"sub": "user123",
"aud": ["https://api.example.com"],
"scope": "contacts.write",
"roles": ["Sales Manager"]
}User-delegated (Authorization Code and CIBA)
Interactive grants (authorization code, CIBA) involve a user who authenticates and consents.
| Step | What happens |
|---|---|
| 1. Request | The client requests scopes (and usually a Resource via resource). |
| 2. Policy | Policies filter which scopes this client/user may receive. Scopes no policy allows are removed from the consent screen before the user sees them. |
| 3. Consent | The user can only approve scopes they are role-eligible for (roles mapped on the Resource). Scopes marked Allow user to decline scope can be declined; the rest must be accepted. |
| 4. Token | The access token includes granted scope values and the roles mapped to those granted scopes, even if the client requested more. See What Ends Up in the Token. |
Important details:
rolesmirrors granted scopes, not the user's full role set. If the user holdsAdmin,Sales Manager, andSales Rep, but only consents tocontacts.read(mapped toSales Rep), the Resource token typically includesroles: ["Sales Rep"]—not every role on the user.- If the user lacks a required role for a scope, they cannot consent to that scope and it will not appear on the token.
- Consent accumulates. There is one consent record per user per app or client, and newly granted scopes are added to it rather than replacing earlier ones. A user who consented to
contacts.readand later tocontacts.writeholds both, so a later request forcontacts.readalone issues a token without prompting again. See How Consent Accumulates. - To put all of the user's tenants, roles, and permissions on the JWT regardless of which scopes were approved, enable Always include all user authorization info on the token on the Inbound App. See Scope Token Settings. That setting is separate from scope↔role mapping on the Resource. For an MCP Server Resource, the same setting lives on the MCP server, or on its dynamic registration template if it uses one.
Note
If a scope requires a role the user does not have, they cannot grant consent for that scope. Only users with matching RBAC roles see and approve those permissions during the consent flow.
Example: user-delegated CRM access
| Scope | Mapped Descope role | What it allows |
|---|---|---|
contacts.read | Sales Rep | List and view contacts |
contacts.write | Sales Manager | Create and update contacts |
- A partner Inbound App requests
contacts.write. - The user must hold Sales Manager (the role linked to that scope) to consent to it.
- On success, the token will include the granted
scope: "contacts.write"and the mappedroles: ["Sales Manager"]. - Your API can authorize using
roles/ permissions underSales Manager, or requirecontacts.writeinscope—or both.
Machine (M2M) and autonomous clients
Client credentials, JWT bearer, and autonomous Agentic Clients have no interactive user consent. There is no end-user role check at consent time.
| Step | What happens |
|---|---|
| 1. Request | The client authenticates as itself (client_credentials, JWT bearer, etc.) and requests scopes for a Resource. |
| 2. Policy | Policies decide which scopes this client may receive (often matched with client.tags or client identity). |
| 3. Token | The access token includes the policy-granted scopes and the roles mapped to those scopes on the API Resource. |
Use this when many M2M clients share tags and Policies grant each tag a specific Resource + scope set. Backends that already authorize from Descope roles and permissions can read roles on the M2M token the same way they do for user tokens, without mapping every OAuth scope in application code.
Example:
- API Resource scope
claims.readis mapped to roleClaims Reader(with permissions your APIs already check). - A Policy allows clients with tag
smithrx-batchto receiveclaims.readon that Resource. - A
client_credentialstoken for such a client includesscope: "claims.read"androles: ["Claims Reader"].
Note
M2M clients do not "hold" user RBAC roles for consent. The roles in the token come from the Resource scope ↔ role mapping for the scopes Policies (and client configuration) grant—not from assigning roles to the client as if it were a user.
User-information scopes
Scopes that share user information with a client, such as profile and email, aren't defined on a Resource. They're attribute scopes, defined once for the project and added to each Inbound App or Federated OIDC App, where they map to the claims that appear in tokens and the /userinfo response.
Enforce on your API
Validate the JWT, then enforce aud, scope, and—if you authorize via RBAC—roles / permissions. See Enforce scopes and Resource claims.
| Approach | When to use |
|---|---|
Require scope | Standard OAuth resource-server pattern; fine-grained per route |
Require roles / permissions | Same RBAC model as first-party apps; permissions live under roles that scopes map to |
| Both | Scope for least-privilege at the OAuth boundary; roles for existing permission checks |
MCP Server Resources
MCP Server Resources define tool-level OAuth scopes for an MCP server. Instead of mapping Resource scopes to RBAC roles, you can map Resource scopes to Connection scopes for when a tool needs credentials from the Connections vault.
| Field | Description |
|---|---|
| Scope name | Machine-friendly string your MCP server enforces (e.g. mcp:schedule_meetings) |
| Connection scopes | OAuth or API permissions on linked Connections to fetch at tool runtime |
| Consent description | Text shown on the user consent screen |
| Allow user to decline scope | Whether the user can uncheck the scope on the consent screen. Off by default, so the scope must be accepted. |
When a client is granted mcp:hubspot, your server can fetch the matching Connection token for HubSpot without storing third-party secrets in the MCP server itself.
Defined MCP scopes appear in the server's discovery document under scopes_supported.
RBAC and MCP Server Resources
Role-based checks for MCP flows use Agentic Identity Hub policies (for example user.roles CONTAINS "scheduler") and consent-flow logic, not scope-to-role fields on the MCP Server Resource definition. API Resources use scope ↔ RBAC on the Resource; MCP Server Resources use scope ↔ Connection mapping on the Resource.
For more configuration details, see MCP server scopes.
Related
- Resources — API and MCP Server Resource overview
- Policies — Which clients and users may receive which scopes
- Creating Inbound Apps — Scope token settings and consent behavior
- Session validation — Enforce
aud,scope, androleson your API
Management
Create API and MCP Server Resources in Descope, associate them with Inbound Apps and agentic Clients, and delete Resources when they are no longer needed.
Attribute Scopes
Map OAuth scopes like profile and email to the user and tenant claims that appear in access tokens, ID tokens, and the /userinfo response.