# How Logto Implements API Access Control: Token-Based RBAC and Scope Verification

> Learn how Logto implements API access control using token-based RBAC and scope verification. Secure your APIs with Logto's OIDC compliant system.

- Repository: [Logto/logto](https://github.com/logto-io/logto)
- Tags: architecture
- Published: 2026-07-06

---

**Logto uses a token-based, scope-driven RBAC system built on OpenID Connect (OIDC), where JWT access tokens carry scope claims that are validated by middleware guards before every protected endpoint.**

The `logto-io/logto` repository is an open-source identity and access management platform that protects its APIs using a layered **API access control** strategy. This implementation combines OIDC-compliant JWT tokens, scope-based middleware enforcement, and flexible role-based access control to secure both user-facing applications and administrative Management API endpoints.

## JWT Access Tokens and Scope Claims

Logto issues **JWT access tokens** containing standard OIDC fields plus a critical `scope` claim that drives authorization decisions. The token structure is strictly defined in [`/packages/schemas/src/types/logto-config/oidc-provider.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/types/logto-config/oidc-provider.ts) through the `accessTokenPayloadGuard` (lines 18-30), which ensures every token contains the required payload shape.

Key token fields include:
- `aud` (audience)
- `jti` (token ID)
- `exp` (expiration)
- `scope` (space-delimited list of granted permissions)

The `scope` claim lists granted permissions such as `openid`, `profile`, or custom API scopes like `api:read`. For full Management API access, Logto reserves the `All` scope within the `PredefinedScope` enum defined in [`/packages/schemas/src/types/user.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/types/user.ts) (lines 81-85).

```typescript
import { accessTokenPayloadGuard } from '@logto/schemas';

// Example payload conforming to the guard
const payload = {
  jti: 'unique-token-id',
  aud: 'logto',
  clientId: 'machine-client',
  accountId: 'user-123',
  grantId: 'grant-456',
  gty: 'client_credentials',
  kind: 'AccessToken',
  scope: 'api:read api:write',  // Space-delimited scopes
};

```

## Middleware Enforcement with Koa-Auth

Every incoming request to a protected Logto endpoint passes through the **Koa-auth middleware** located in [`/packages/core/src/middleware/koa-auth/index.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/middleware/koa-auth/index.ts). This middleware extracts the bearer token from the `Authorization` header, validates it against the `accessTokenPayloadGuard`, and verifies that the token's `scope` claim satisfies the endpoint's required permissions (lines 1-12).

If the scope check fails, the middleware returns a `403 Forbidden` error immediately, preventing unauthorized access before the route handler executes. For routes requiring specific permissions, Logto uses a `requireScopes` helper that wraps the validation logic.

```typescript
import Router from 'koa-router';
import { requireScopes } from '#src/middleware/koa-auth';

const router = new Router();

router.get(
  '/api/protected-resource',
  requireScopes(['api:read']),  // Middleware validates token.scope
  async (ctx) => {
    ctx.body = { data: 'Protected content' };
  }
);

```

## RBAC: Roles and Predefined Scopes

Logto implements **Role-Based Access Control (RBAC)** by storing roles and permissions in the database and mapping them to the `PredefinedScope` values. When issuing tokens for machine-to-machine clients, Logto derives the token's scopes from the client's assigned roles.

The seeding script in [`/packages/schemas/src/seeds/management-api.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/seeds/management-api.ts) (lines 47-54) demonstrates this by creating a default "Management API access" role linked to the `All` scope. This role grants comprehensive access to administrative functions and is automatically attached to the built-in admin tenant during initialization.

The `PredefinedScope` enum in [`/packages/schemas/src/types/user.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/types/user.ts) (lines 81-84) acts as the source of truth for system-level permissions, ensuring consistent scope naming across the platform.

## Application-Level Access Control

Beyond RBAC, Logto supports **fine-grained application-level access control** through the `ApplicationAccessControl` object. This system allows administrators to define explicit allow-lists containing specific user IDs, user role IDs, organization IDs, and organization role rules.

The utilities in [`/packages/core/src/routes/applications/application-access-control/utils.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/routes/applications/application-access-control/utils.ts) manage these rules:
- `ApplicationAccessControl` interface (lines 6-15) defines the rule structure
- `assertApplicationAccessControlHasRules` (lines 17-24) validates that at least one rule exists before the feature can be enabled

When application-level ACL is active, the `accessControlGuard` reads these rule tables to verify if the caller's token (and its associated user/role information) matches any allowed entry.

```typescript
import {
  ApplicationAccessControl,
  assertApplicationAccessControlHasRules,
} from '#src/routes/applications/application-access-control/utils';

const accessControl: ApplicationAccessControl = {
  userIds: ['user-1', 'user-2'],
  userRoleIds: ['role-admin'],
  organizationIds: ['org-123'],
  organizationRoleRules: [],
};

// Throws 422 if no rules are defined
assertApplicationAccessControlHasRules(accessControl);

```

## Securing the Management API

The **Management API** represents Logto's most privileged endpoint set, requiring tokens that carry the `PredefinedScope.All` scope. As implemented in [`/packages/core/src/middleware/koa-auth/index.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/middleware/koa-auth/index.ts) (lines 110-112), endpoints within the Management API namespace explicitly check for this "all-access" scope.

During system initialization, the seed script in [`/packages/schemas/src/seeds/management-api.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/seeds/management-api.ts) (lines 47-55) creates a dedicated Management API role pre-configured with the `All` scope. This role is automatically provisioned for the admin tenant, ensuring administrative functions remain accessible only to properly authorized automation scripts and console users.

## Summary

- **Token-based architecture**: Logto issues JWT access tokens containing OIDC-standard fields plus a `scope` claim that lists granted permissions, defined in [`/packages/schemas/src/types/logto-config/oidc-provider.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/types/logto-config/oidc-provider.ts).
- **Middleware validation**: The Koa-auth middleware in [`/packages/core/src/middleware/koa-auth/index.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/middleware/koa-auth/index.ts) validates bearer tokens and enforces required scopes before allowing request processing.
- **RBAC implementation**: Roles map to `PredefinedScope` values (such as `All` for Management API access) stored in [`/packages/schemas/src/types/user.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/types/user.ts).
- **Granular controls**: Application-level access control in [`/packages/core/src/routes/applications/application-access-control/utils.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/routes/applications/application-access-control/utils.ts) enables fine-grained rules for specific users, roles, and organizations.
- **Management protection**: The Management API requires the special `All` scope, provisioned through the seeding script at [`/packages/schemas/src/seeds/management-api.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/seeds/management-api.ts).

## Frequently Asked Questions

### How does Logto validate API access token scopes?

Logto validates scopes through the Koa-auth middleware located in [`/packages/core/src/middleware/koa-auth/index.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/middleware/koa-auth/index.ts). The middleware extracts the JWT from the `Authorization` header, verifies its signature and structure against the `accessTokenPayloadGuard`, and checks that the token's `scope` claim includes the permissions required by the endpoint. If validation fails, the middleware returns a `403 Forbidden` response before the route handler executes.

### What is the difference between RBAC and application-level access control in Logto?

**RBAC** (Role-Based Access Control) operates at the system level, mapping machine-to-machine clients and users to predefined scopes like `All` or `api:read` through database roles. **Application-level access control** provides finer granularity within specific applications, allowing administrators to create explicit allow-lists of user IDs, role IDs, and organization IDs that can access a particular application, as defined in [`/packages/core/src/routes/applications/application-access-control/utils.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/routes/applications/application-access-control/utils.ts).

### How is the Logto Management API protected?

The Management API requires access tokens carrying the `PredefinedScope.All` scope, which grants comprehensive administrative privileges. This scope is defined in [`/packages/schemas/src/types/user.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/types/user.ts) and assigned through a dedicated Management API role created during system initialization in [`/packages/schemas/src/seeds/management-api.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/seeds/management-api.ts). The middleware explicitly checks for this scope (lines 110-112 in [`/packages/core/src/middleware/koa-auth/index.ts`](https://github.com/logto-io/logto/blob/main//packages/core/src/middleware/koa-auth/index.ts)) to protect administrative endpoints.

### What fields are included in a Logto access token?

According to the `accessTokenPayloadGuard` in [`/packages/schemas/src/types/logto-config/oidc-provider.ts`](https://github.com/logto-io/logto/blob/main//packages/schemas/src/types/logto-config/oidc-provider.ts), Logto access tokens include standard OIDC fields such as `jti` (token ID), `aud` (audience), `exp` (expiration), `clientId`, `accountId`, and `grantId`, plus a critical `scope` field containing space-delimited permissions. The `kind` field is set to `AccessToken` to distinguish these from other JWT types in the system.