# The Role of JWT in Logto's Security Model: OIDC Implementation and Best Practices

> Discover how Logto leverages JWTs for secure, stateless authentication with OIDC. Learn about RSA-signed tokens, customizable claims, and JWKS validation for robust security.

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

---

**Logto uses JSON Web Tokens (JWTs) as the cryptographic foundation of its OpenID Connect (OIDC) implementation, issuing RSA-signed access tokens and ID tokens that enable stateless authentication, carry customizable identity claims, and support secure validation via JWKS endpoints without requiring database lookups for each request.**

Logto (logto-io/logto) is an open-source identity and access management platform built on the OpenID Connect standard. Understanding **the role of JWT in Logto's security model** reveals how the platform achieves scalable, stateless authentication while maintaining strong security guarantees through cryptographic signing, custom claim injection, and session-based revocation mechanisms.

## Stateless Access Tokens and Self-Contained Validation

Logto implements **stateless access tokens** as signed JWTs, allowing resource servers to validate authentication without querying the authorization server database. When a client completes the OIDC flow, Logto's token endpoint (implemented in [`packages/core/src/routes/api/token.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/api/token.ts)) issues an access token signed with an RSA private key.

Resource servers validate these tokens using the **JSON Web Key Set (JWKS)** endpoint exposed at [`/.well-known/jwks.json`](https://github.com/logto-io/logto/blob/main//.well-known/jwks.json). This endpoint publishes the public key corresponding to the private key held by Logto Core, enabling signature verification without network calls to the authorization server. As implemented in [`packages/core/src/utils/jwt.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/utils/jwt.ts), this approach ensures that token validation requires only cryptographic operations, not database lookups.

### Scope and Audience Enforcement

Logto enforces authorization boundaries through standard OIDC claims embedded in the JWT payload. The `scp` (scopes) and `aud` (audience) claims specify the resources and permissions the token grants. When protected APIs receive a token, they verify these claims to ensure the token was issued for the specific resource and contains the necessary permissions, preventing token misuse across different services.

## ID Tokens and Identity Verification

In addition to access tokens, Logto returns an **ID token**—also a JWT—that contains the authenticated user's identity claims. These tokens include standard OIDC claims such as `sub` (subject identifier), `email`, and `name`, allowing client applications to verify user identity cryptographically.

The client can validate the ID token's signature against the JWKS endpoint and extract the user profile directly from the token payload. This self-contained identity verification eliminates the need for separate userinfo endpoint calls in many scenarios, reducing latency and dependency on the authorization server's availability.

## Custom Claims and the JWT Customizer

Logto extends standard JWT functionality through the **JWT Customizer** feature, defined in [`packages/schemas/src/types/logto-config/jwt-customizer.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/logto-config/jwt-customizer.ts). This configuration allows administrators to inject **custom claims** into access tokens before signing.

When Logto generates a token, it executes the customizer script to merge static or dynamic values into the payload. This enables embedding tenant-specific data—such as roles, permissions, or tenant IDs—directly within the token. For example, a customizer might add a `customRole` claim based on the user's database record, making authorization decisions available at the edge without additional database queries.

## Session Management and Token Revocation

While JWTs are inherently stateless, Logto implements a **revocation mechanism** through session tracking. The platform stores a session identifier (`sid`) inside the JWT payload, as defined in [`packages/schemas/src/types/user-sessions.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/user-sessions.ts) and managed through utilities in [`packages/shared/src/utils/session.ts`](https://github.com/logto-io/logto/blob/main/packages/shared/src/utils/session.ts).

When a session is revoked—whether through user logout or administrative action—the corresponding session record is removed from Logto's database. Subsequent requests presenting a JWT containing that `sid` are rejected, even if the token hasn't expired. This hybrid approach maintains the performance benefits of stateless tokens for most requests while providing immediate revocation capabilities when necessary.

## Cryptographic Security and Key Management

Logto signs all JWTs using **RSA-256 (RS256)** asymmetric cryptography. The private key remains secured within the Logto Core service, while the public key is distributed via the JWKS endpoint. This architecture provides:

- **Integrity**: RSA-SHA256 signatures prevent token tampering
- **Authenticity**: Only tokens signed by Logto's private key are accepted  
- **Optional Confidentiality**: While most deployments use signed tokens for performance, Logto supports JWT encryption (JWE) for scenarios requiring payload confidentiality

## Implementing JWT Validation with Logto

The following examples demonstrate how to work with Logto's JWT implementation using the `jose` library.

### Generating Signed Access Tokens

When extending Logto or building compatible services, you can generate tokens using the same patterns found in [`packages/core/src/utils/jwt.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/utils/jwt.ts):

```typescript
import { SignJWT } from 'jose'
import { getPrivateKey } from '@/utils/key' // Logto's RSA private key helper

export async function createAccessToken(payload: Record<string, unknown>) {
  const privateKey = await getPrivateKey()
  
  // Standard JWT claims (iss, sub, aud, exp, iat) + custom claims from payload
  const jwt = await new SignJWT(payload)
    .setProtectedHeader({ alg: 'RS256', typ: 'JWT' })
    .setIssuer('https://logto.dev')
    .setAudience('your-api')
    .setExpirationTime('2h')
    .setIssuedAt()
    .sign(privateKey)

  return jwt
}

```

### Verifying Tokens on Resource Servers

Resource servers validate tokens using the JWKS endpoint provided by Logto Core:

```typescript
import { jwtVerify, importJWK } from 'jose'

// JWKS URL exposed by Logto Core
const jwksUrl = 'https://logto.dev/.well-known/jwks.json'

export async function verifyAccessToken(token: string) {
  const { payload } = await jwtVerify(token, async (header) => {
    const jwks = await fetch(jwksUrl).then((r) => r.json())
    const key = jwks.keys.find((k: any) => k.kid === header.kid)
    if (!key) throw new Error('JWK not found')
    return importJWK(key, header.alg)
  })
  
  // payload now contains sub, scp, custom claims, etc.
  return payload
}

```

### Configuring Custom Claims

Administrators can add custom claims through Logto's JWT Customizer API:

```json
{
  "key": "jwt.accessToken",
  "script": "return { ...payload, customRole: 'admin' }"
}

```

When Logto signs the token, the script executes and the resulting JWT includes the custom data:

```json
{
  "sub": "user-123",
  "customRole": "admin",
  "...": "other standard claims"
}

```

## Summary

- Logto uses **stateless JWTs** for both access tokens and ID tokens, enabling scalable OIDC-compliant authentication.
- **JWKS endpoint** ([`/.well-known/jwks.json`](https://github.com/logto-io/logto/blob/main//.well-known/jwks.json)) allows resource servers to validate tokens without database queries.
- The **JWT Customizer** ([`packages/schemas/src/types/logto-config/jwt-customizer.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/logto-config/jwt-customizer.ts)) supports dynamic injection of tenant-specific claims.
- **Session identifiers** (`sid`) embedded in JWTs enable token revocation while maintaining stateless benefits.
- **RSA-256 signing** provides cryptographic integrity and authenticity, with optional JWE encryption available.

## Frequently Asked Questions

### How does Logto validate JWTs without database lookups?

Logto signs JWTs with an RSA private key and publishes the corresponding public key via the JWKS endpoint at [`/.well-known/jwks.json`](https://github.com/logto-io/logto/blob/main//.well-known/jwks.json). Resource servers validate signatures locally using these public keys, verifying the token's authenticity and integrity through cryptographic operations alone. This stateless approach, implemented in [`packages/core/src/utils/jwt.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/utils/jwt.ts), eliminates the need to query the authorization server database for each validation request.

### What is the JWT Customizer in Logto?

The JWT Customizer is a configuration feature defined in [`packages/schemas/src/types/logto-config/jwt-customizer.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/logto-config/jwt-customizer.ts) that allows administrators to inject custom claims into JWT payloads before signing. Administrators provide scripts that execute during token generation, enabling dynamic insertion of data such as user roles, tenant identifiers, or application-specific metadata directly into the token.

### How does Logto handle token revocation with stateless JWTs?

Logto embeds a session identifier (`sid`) claim within each JWT, as defined in [`packages/schemas/src/types/user-sessions.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/user-sessions.ts). While the token remains valid cryptographically until expiration, Logto maintains session records in its database. When a user logs out or an admin revokes the session, the corresponding record is deleted, and Logto rejects any requests bearing tokens containing that `sid`, effectively revoking the token without breaking stateless validation for active sessions.

### What cryptographic algorithms does Logto use for JWT signing?

Logto uses **RS256** (RSA with SHA-256) as the default signing algorithm for all JWTs. The platform stores the RSA private key securely within Logto Core while exposing the public key through the JWKS endpoint. This asymmetric approach ensures that only the authorization server can sign tokens, while any service can verify them. Logto also supports optional JWT encryption (JWE) for deployments requiring payload confidentiality.