Logto Security Best Practices: Enterprise-Grade Hardening in the Source Code
Logto implements defense-in-depth security through Helmet-based HTTP headers, automatic secret rotation, configurable MFA policies, scoped Personal Access Tokens, and built-in rate limiting, all enforced at the middleware and database layers.
Logto is an open-source identity and access management platform that embeds enterprise security controls directly into its architecture. Understanding Logto security best practices requires examining how the codebase implements OWASP guidelines, secret management, and tenant isolation. This analysis explores the concrete implementations in the logto-io/logto repository that protect authentication flows and sensitive data.
HTTP Security Headers and Content Security Policy
Logto uses Helmet middleware to enforce OWASP-recommended security headers across all applications (core, console, and experience).
Centralized Header Configuration
The koa-security-headers.ts middleware in packages/core/src/middleware/koa-security-headers.ts defines baseline security settings through the basicSecurityHeaderSettings object. This configuration enforces Strict-Transport-Security (HSTS) with long max-age values and enables Cross-Origin Opener Policy (COOP) and Cross-Origin Embedder Policy (COEP) protections.
Dynamic CSP Per Tenant
Logto tailors Content-Security-Policy directives per application context. The implementation defines specific source arrays including experienceScriptSource for trusted JavaScript origins, experienceConnectSource for API endpoints and CDNs, and avatarCropImageSources for image upload functionality. Production guards ensure development-only relaxations—such as Google One-Tap iframe support—never reach production builds.
Extending CSP for Custom Scripts
When organizations need to whitelist additional script sources, they can leverage the internal createSecurityHeaderSettings factory:
// src/tenant/custom-csp.ts
import { getTenantId } from '@logto/core';
import { createSecurityHeaderSettings } from '@logto/core/src/middleware/koa-security-headers';
export const getCustomHeader = (tenantId: string) => {
const { getExperienceSecurityHeaderSettings } =
createSecurityHeaderSettings(tenantId);
// Append a trusted script host for this tenant only
const customCsp = {
scriptSrc: ['https://trusted.example.com/'],
};
return getExperienceSecurityHeaderSettings(customCsp);
};
This approach merges custom sources with secure defaults while respecting the isProduction environment checks defined in lines 15-22 of the middleware file.
Secret Management and Cryptographic Key Rotation
Logto never hard-codes secrets. Instead, it persists encrypted configuration in the database and implements automated rotation mechanisms.
OIDC Cookie Key Storage
Cookie signing keys are stored in the logto_config table under the oidc.cookieKeys key, as defined in packages/schemas/src/types/logto-config/index.ts. The system maintains multiple valid keys simultaneously to ensure zero-downtime rotation.
Automated Rotation via CLI
Administrators rotate keys using the built-in CLI:
# Rotate cookie keys – generates a fresh key, keeps the previous one for graceful rollout
pnpm cli config rotate-cookie-keys
This command executes migration logic similar to 1.0.0_rc.1-1676190092-migrate-admin-data.ts, which safely inserts new keys while preserving existing sessions.
Configuration Library
The LogtoConfigLibrary in packages/core/src/libraries/logto-config.ts handles encrypted reads and writes for sensitive values including JWT signing keys and OIDC private keys, ensuring secrets never exist in environment variables or code repositories.
Multi-Factor Authentication Implementation
Logto supports TOTP, WebAuthn, and backup codes through a flexible policy engine embedded in the sign-in experience schema.
MFA Policy Configuration
The JSONB schema in packages/schemas/src/foundations/jsonb-types/sign-in-experience.ts (lines 190-210) defines three policy levels: Mandatory requires MFA on every authentication, Optional allows user-configured MFA, and Adaptive enables risk-based step-up authentication.
Enforcing Mandatory MFA
Administrators configure tenant-wide MFA requirements via the Admin API:
await fetch(`${tenantEndpoint}/api/tenants/${tenantId}/sign-in-experience`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${adminToken}` },
body: JSON.stringify({
mfa: {
// Force MFA on every sign‑in
policy: 'mandatory',
factors: ['totp', 'webauthn']
},
}),
});
The require_mfa_verification check in the authentication flow validates these policies before issuing tokens.
Personal Access Tokens and Scoped Authorization
Logto implements scoped API access through Personal Access Tokens (PATs) with strict isolation guarantees.
Token Architecture
PATs are stored in the personal_access_tokens table with Row-Level Security (RLS) policies that isolate tenant data. The token type is explicitly declared as urn:logto:token-type:personal_access_token in packages/core/src/oidc/grants/token-exchange/types.ts.
Programmatic Token Creation
import { createPersonalAccessToken } from '@logto/core/src/queries/personal-access-token';
const pat = await createPersonalAccessToken({
name: 'CI‑pipeline',
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days
scopes: ['read:users', 'write:applications']
});
console.log('PAT value (store securely):', pat.value);
The database schema and RLS setup are defined in packages/schemas/alterations/1.20.0-1723448981-personal-access-tokens.ts.
Rate Limiting and Brute-Force Protection
The Sentinel middleware protects authentication endpoints from abuse through IP and device-based throttling.
Message Rate Guarding
The message-rate-guard.ts file in packages/core/src/sentinel/ implements limits on login attempts, blocking abusive patterns before they reach the authentication logic. This prevents credential stuffing and brute-force attacks against the OIDC endpoints.
Summary
- HTTP Security: Helmet-based headers with tenant-specific CSP, HSTS, and COOP/COEP protections enforced in
koa-security-headers.ts - Secret Rotation: Automated cookie key rotation via CLI and encrypted storage in
logto_configtable accessed throughLogtoConfigLibrary - MFA Policies: Flexible multi-factor configuration through
sign-in-experienceJSONB schema supporting mandatory, optional, and adaptive modes - Token Security: Scoped PATs with RLS isolation and explicit token type declarations (
urn:logto:token-type:personal_access_token) - Attack Prevention: Built-in rate limiting through Sentinel middleware protecting against brute-force attempts
Frequently Asked Questions
How does Logto handle Content Security Policy violations?
Logto implements CSP through the koa-security-headers.ts middleware, which configures Helmet with strict directives for script-src, style-src, and connect-src. The system dynamically adjusts allowed sources based on tenant configuration while maintaining production guards that prevent unsafe development settings from deploying to production environments.
What is the recommended approach for rotating OIDC signing keys?
Use the CLI command pnpm cli config rotate-cookie-keys to generate new keys while maintaining backward compatibility. This updates the oidc.cookieKeys array in the logto_config table, allowing existing sessions to remain valid while new sessions use the fresh key. The rotation logic follows the migration pattern established in 1.0.0_rc.1-1676190092-migrate-admin-data.ts.
How does Logto protect against brute-force authentication attacks?
Logto employs the Sentinel middleware (message-rate-guard.ts) to limit login attempts per IP address and device fingerprint. This rate-limiting layer intercepts suspicious traffic patterns before they reach the OIDC grant handlers, effectively mitigating credential stuffing and automated brute-force attempts.
Are Personal Access Tokens isolated between tenants?
Yes. PATs implement Row-Level Security (RLS) policies at the database level as defined in 1.20.0-1723448981-personal-access-tokens.ts, ensuring tokens created in one tenant cannot access resources in another. The tokens use the specific type URI urn:logto:token-type:personal_access_token and store only hashed identifiers in the database, with the full value displayed only once during creation.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →