Configuring Logto API Resources and Scopes for Authorization

Logto implements OAuth 2.0 / OpenID Connect authorization by separating API resources from scopes, allowing you to define protected APIs as resources and granular permissions as scopes, then assign specific scope whitelists to applications that clients request during the authorization flow.

Logto is an open-source identity and access management platform that follows the OAuth 2.0 and OpenID Connect standards. Configuring Logto API resources and scopes for authorization involves defining protected APIs as resources, creating granular scopes for those resources, and linking allowed scopes to applications so that access tokens carry only the permissions granted by the user. This architecture, implemented in the logto-io/logto repository, enables fine-grained access control across distributed services.

Understanding the Resource and Scope Architecture

Logto models authorization through three interconnected entities: resources, scopes, and applications. This separation allows you to reuse scope names across multiple APIs while maintaining distinct permission boundaries.

Resource Definition

In packages/schemas/src/types/resource.ts, a resource represents a protected API endpoint. Each resource stores an identifier, name, description, and an array of associated scopes. The resource acts as the top-level container for permissions, allowing you to group related scopes under a single API entity.

Scope Model

Individual scopes are defined in packages/schemas/src/types/scope.ts as first-class entities containing id, name, description, and resourceId fields. The file exports scopeResponseGuard for runtime validation, ensuring that scope data conforms to the expected schema before persistence. Scopes are simple strings (such as read:user or write:order) that represent specific operations a client can perform against the resource.

Application Linkage

Applications (OAuth clients) store their permitted scopes in the scopes field, as defined in packages/schemas/src/types/application.ts. This field acts as a whitelist that determines which scopes the client is allowed to request during the authorization flow. When a user authenticates, Logto validates that the requested scopes are a subset of the application's stored scopes.

How Logto Evaluates Authorization Scopes

The authorization flow in Logto evaluates scopes through a four-stage filtering process:

  1. Application-level whitelist – The client can only request scopes explicitly listed in the application's scopes field.
  2. Tenant-level configuration – Global tenant settings enable or disable specific scopes (such as Roles or Organizations); disabled scopes are filtered out before the consent page renders.
  3. Consent page – The user interface displays the intersection of requested scopes and available scopes, allowing the user to approve or deny each permission individually.
  4. Token issuance – The final access token contains a space-separated scope claim listing only the approved scopes, which the resource server validates against required permissions.

Configuring Resources via the Management API

Administrators manage resources and scopes through Logto's Management API. The API payloads mirror the schema definitions found in the source code, ensuring type safety between the backend and client requests.

Creating a New Resource with Scopes

Use the POST /api/resources endpoint to create a resource and define its scopes in a single request:

POST https://<logto-host>/api/resources
Content-Type: application/json
Authorization: Bearer <admin-access-token>

{
  "name": "Orders API",
  "description": "Access to order data",
  "scopes": [
    { "name": "order:read",  "description": "Read order information" },
    { "name": "order:write", "description": "Create or modify orders" }
  ]
}

The scopes array in the request body corresponds to the Scope type defined in packages/schemas/src/types/scope.ts.

Adding Scopes to Existing Resources

To append scopes to an existing resource without recreating it, target the resource-specific scopes endpoint:

POST https://<logto-host>/api/resources/123456/scopes
Content-Type: application/json
Authorization: Bearer <admin-access-token>

{
  "name": "order:delete",
  "description": "Delete an order"
}

This endpoint creates a new scope entity and associates it with the resource identified by 123456.

Assigning Scopes to Applications

Before a client can request scopes, you must update the application configuration to whitelist those permissions:

PATCH https://<logto-host>/api/applications/abcdef
Content-Type: application/json
Authorization: Bearer <admin-access-token>

{
  "scopes": [
    "order:read",
    "order:write"
  ]
}

This modification updates the application's scopes field in packages/schemas/src/types/application.ts, enabling the authorization server to validate future requests.

Requesting and Validating Scopes in the OAuth Flow

After configuration, the runtime flow handles scope validation according to the logic in packages/toolkit/core-kit/src/openid.ts.

Authorization Request

Clients initiate the flow by requesting specific scopes via the scope query parameter:

GET https://<logto-host>/oidc/auth
?client_id=abcdef
&redirect_uri=https%3A%2F%2Fmyapp.com%2Fcallback
&response_type=code
&scope=order:read%20order:write
&state=xyz

Logto parses this parameter, validates the scopes against the application whitelist and tenant configuration, and stores the authorized set in the interaction session.

Token Validation in Protected Endpoints

Resource servers must verify that incoming access tokens contain the required scope. A Node.js implementation using the Logto SDK appears as follows:

import { verifyAccessToken } from '@logto/node';

app.get('/orders/:id', async (req, res) => {
  const token = await verifyAccessToken(req.headers.authorization);
  if (!token.scope.includes('order:read')) {
    return res.status(403).json({ error: 'Insufficient scope' });
  }
  // ... fetch and return order data
});

The scope claim in the token is a space-separated string of granted permissions, matching the format defined in the OAuth 2.0 specification.

Summary

  • Resources represent protected APIs and contain arrays of scopes, defined in packages/schemas/src/types/resource.ts.
  • Scopes are first-class entities with name, description, and resourceId fields, validated by scopeResponseGuard in packages/schemas/src/types/scope.ts.
  • Applications whitelist allowed scopes in their configuration, stored in the scopes field per packages/schemas/src/types/application.ts.
  • The Management API provides endpoints to create resources (POST /api/resources), add scopes (POST /api/resources/:id/scopes), and configure applications (PATCH /api/applications/:id).
  • The authorization flow validates requested scopes against application whitelists and tenant settings before issuing tokens containing space-separated scope claims.

Frequently Asked Questions

What is the difference between a resource and a scope in Logto?

A resource represents the protected API itself (such as "Orders API"), while a scope represents a specific permission within that API (such as "read orders" or "write orders"). Resources act as containers that group related scopes together, allowing you to manage permissions at both the API level and the individual operation level.

How do I restrict which scopes an application can request?

Update the application's scopes field via the Management API (PATCH /api/applications/:id) to include only the specific scope names you want to allow. Logto validates every authorization request against this whitelist, rejecting any request for scopes not explicitly listed in the application configuration.

Can I reuse scope names across different API resources?

Yes. Because scopes are linked to resources via the resourceId field, you can define identical scope names (such as read:data) on multiple resources. This allows consistent naming conventions across services while maintaining distinct permission boundaries, as the resource identifier distinguishes which API the scope belongs to.

How does Logto handle OpenID Connect standard scopes?

Logto recognizes standard OIDC scopes (such as profile, email, and openid) through the logic in packages/toolkit/core-kit/src/openid.ts. These scopes map to specific claims in the ID token and can be toggled at the tenant level. Custom scopes defined for your API resources work alongside these standard scopes in the same authorization request.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →