# How to Manage API Resources and Scopes in Logto: A Complete Guide

> Learn to effectively manage API resources and scopes in Logto. Understand audiences and granular permissions using the Management API or Admin Console for robust security. Get the complete guide now.

- Repository: [Logto/logto](https://github.com/logto-io/logto)
- Tags: how-to-guide
- Published: 2026-07-05

---

**Logto manages API resources and scopes through a database-backed system where resources are identified by unique indicators (audiences) and scopes define granular permissions, accessible via Management API endpoints or the Admin Console UI.**

In the `logto-io/logto` repository, API resources and scopes form the authorization backbone for protecting external APIs. Each API resource represents a logical entity that client applications can request access to, while scopes define the specific operations permitted within that resource. This guide explains the core implementation based on the source code and provides practical examples for managing these entities.

## Understanding API Resources and Scopes in Logto

### What is an API Resource?

An **API resource** is a logical representation of an external API that client applications can invoke. According to [`packages/schemas/src/types/resource.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/resource.ts), each resource contains:

- **Indicator**: A unique URL-like identifier (e.g., `https://myapp.com/api`) that serves as the audience (`aud`) claim in JWT tokens
- **Name**: A human-readable label for the Admin Console
- **Default flag**: A boolean marking whether this is the default Management API (only one allowed per tenant)
- **Permissions**: An array of scopes defining available operations

### What are Scopes (Permissions)?

A **scope** (also called a permission) belongs to a single API resource and describes a granular operation. Defined in [`packages/schemas/src/types/scope.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/scope.ts), scopes are stored within the resource's `permissions` array and exposed through the Management API. Common examples include `read:user` or `write:orders`.

## Creating and Configuring API Resources

### Define the Resource Indicator

When creating a resource, you must specify a unique **indicator** that matches the `aud` claim expected by your API. The indicator acts as the audience identifier during token validation.

### Add Scopes to the Resource

Scopes are attached to resources and validated during token issuance. Each scope requires a name (no spaces) and optional description.

### Create an API Resource via Management API

The [`packages/core/src/routes/api-resource.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/api-resource.ts) file implements the CRUD endpoints. Below is a TypeScript example for creating a resource:

```typescript
import fetch from 'node-fetch';

const LOGTO_ADMIN_URL = 'https://logto.example.com/api';
const ACCESS_TOKEN = 'YOUR_MANAGEMENT_API_TOKEN';

async function createApiResource() {
  const response = await fetch(`${LOGTO_ADMIN_URL}/api-resources`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${ACCESS_TOKEN}`,
    },
    body: JSON.stringify({
      name: 'My Awesome API',
      indicator: 'https://my-awesome-api.com/api',
      default: false,
    }),
  });

  const data = await response.json();
  console.log('Created API resource →', data);
}

createApiResource();

```

### Add Scopes to an Existing Resource

To add permissions to a resource, POST to the resource-specific permissions endpoint:

```typescript
async function addScope(resourceId: string) {
  const response = await fetch(
    `${LOGTO_ADMIN_URL}/api-resources/${resourceId}/permissions`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${ACCESS_TOKEN}`,
      },
      body: JSON.stringify({
        name: 'read:orders',
        description: 'Read order information',
      }),
    }
  );

  const permission = await response.json();
  console.log('Added permission →', permission);
}

```

## Managing Resources Programmatically

### Retrieve and Update Resources

The Management API supports full CRUD operations as implemented in [`packages/core/src/routes/api-resource.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/api-resource.ts):

- **GET** `/api-resources` – List all resources with their scopes
- **PATCH** `/api-resources/:id` – Update resource name or indicator
- **DELETE** `/api-resources/:id` – Remove resource and associated scopes

Example deletion:

```typescript
async function deleteApiResource(resourceId: string) {
  await fetch(`${LOGTO_ADMIN_URL}/api-resources/${resourceId}`, {
    method: 'DELETE',
    headers: {
      Authorization: `Bearer ${ACCESS_TOKEN}`,
    },
  });

  console.log(`API resource ${resourceId} deleted`);
}

```

### Admin Console Implementation

The React-based Admin Console provides UI components for these operations in `packages/console/src/pages/api-resources/*`, offering a visual interface for creating resources and managing their scopes without writing code.

## Token Issuance and Verification

When clients request tokens, Logto validates the resource against stored indicators. The [`packages/core/src/services/token-service.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/services/token-service.ts) file handles:

1. **Resource validation**: Checking the `resource` parameter against the `resources` table
2. **Scope filtering**: Ensuring requested scopes exist in the resource's permissions array
3. **Audience assignment**: Setting the token's `aud` claim to the resource indicator

Clients request tokens by specifying the resource indicator:

```typescript
import { LogtoClient } from '@logto/client';

const logto = new LogtoClient({
  endpoint: 'https://logto.example.com',
  resource: 'https://my-awesome-api.com/api',
});

async function getToken() {
  const token = await logto.getAccessToken();
  console.log('Access token for resource →', token);
}

```

## The Default Management API

Logto automatically creates a default Management API resource during initialization via [`packages/schemas/src/seeds/management-api.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/seeds/management-api.ts). This special resource:

- Uses an indicator generated by `getManagementApiResourceIndicator` in [`packages/schemas/src/utils/management-api.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/utils/management-api.ts)
- Is automatically granted to machine-to-machine (M2M) clients
- Powers the Admin Console and tunnel CLI functionality

The database alteration in [`packages/schemas/alterations/1.9.2-1695198741-remove-m2m-app-admin-access-switch.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/alterations/1.9.2-1695198741-remove-m2m-app-admin-access-switch.ts) enforces that only one resource can be marked as default, preventing configuration conflicts.

## Summary

- **API resources** in Logto are defined by unique indicators (audiences) stored in the `resources` table, implemented in [`packages/schemas/src/types/resource.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/resource.ts)
- **Scopes** (permissions) are resource-specific operations defined in [`packages/schemas/src/types/scope.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/scope.ts) and managed via the `POST /api-resources/:id/permissions` endpoint
- **Management API** endpoints in [`packages/core/src/routes/api-resource.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/api-resource.ts) provide programmatic CRUD operations for both resources and scopes
- **Token validation** occurs in [`packages/core/src/services/token-service.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/services/token-service.ts), which verifies resource indicators and filters scopes during JWT issuance
- **Default Management API** is automatically seeded and restricted to one per tenant through database constraints

## Frequently Asked Questions

### What is the difference between an API resource indicator and a scope in Logto?

The **indicator** is a unique URL-like string (e.g., `https://api.example.com`) that identifies the API resource itself and becomes the `aud` claim in access tokens. A **scope** is a granular permission string (e.g., `read:users`) that defines specific operations allowed on that resource. While the indicator identifies *what* API is being accessed, scopes define *how* the client can interact with it.

### How do I obtain a Management API token to manage API resources programmatically?

Create a machine-to-machine (M2M) application in the Logto Admin Console and grant it the appropriate Management API scopes (such as `api:read` and `api:create`). Then use the OIDC token endpoint with the Management API indicator—generated by `getManagementApiResourceIndicator` in [`packages/schemas/src/utils/management-api.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/utils/management-api.ts)—to request an access token. This token authorizes requests to the `/api-resources` endpoints.

### Can I have multiple default API resources in Logto?

No. Logto enforces a unique constraint allowing only one default API resource per tenant. This restriction is implemented in the database alteration file [`packages/schemas/alterations/1.9.2-1695198741-remove-m2m-app-admin-access-switch.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/alterations/1.9.2-1695198741-remove-m2m-app-admin-access-switch.ts). The default resource is reserved for the Logto Management API, which is automatically seeded during installation via [`packages/schemas/src/seeds/management-api.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/seeds/management-api.ts).

### How does Logto validate the resource parameter during token issuance?

When a client requests a token with a specific `resource` parameter, the [`token-service.ts`](https://github.com/logto-io/logto/blob/main/token-service.ts) in `packages/core/src/services/` validates that the indicator exists in the `resources` table. It then filters the requested scopes against the permissions stored in that resource's `permissions` array, ensuring only authorized scopes are included in the final JWT's `scope` claim.