Customizing Logto: 8 Core Entry Points for Extending Authentication Behavior

Logto provides eight officially supported extension points—Inline Hooks, Custom JWT Workers, custom sign-in UI assets, CSP configuration, custom data fields, tenant IDs, custom domains, and connector metadata—that let developers modify authentication flows, token payloads, and user interfaces without modifying core source code.

Customizing Logto behavior centers on its declarative extension architecture rather than code forks. The platform exposes TypeScript-validated guards, Management API endpoints, and CLI tooling that let you inject custom logic at specific lifecycle stages. Whether you need to run JavaScript after user verification, rewrite JWTs via Cloudflare Workers, or serve a completely custom sign-in experience, these entry points provide safe, upgradeable hooks into the authentication pipeline.

Authentication Flow Extensions: Inline Hooks

Inline Hooks allow you to execute custom JavaScript during critical authentication transitions. The system supports two primary hook types defined in packages/schemas/src/types/logto-config/inline-hook.ts (lines 8‑22): PostFirstFactorVerification and PostSignIn.

These hooks accept a script string, environment variables, and an execution error policy. When enabled, Logto sandboxes and executes your code immediately after the specified event fires.

import { LogtoInlineHookKey } from 'logto/schemas';

const hookPayload = {
  script: 'module.exports = async ({ user }) => { console.log("User signed in:", user.id); };',
  enabled: true,
  onExecutionError: 'allow',
};

await fetch(`${endpoint}/api/hook`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}` },
  body: JSON.stringify({
    hookType: LogtoInlineHookKey.PostSignIn,
    ...hookPayload,
  }),
});

The inlineHookGuard validates all payloads against the schema defined in the source file, ensuring type safety for hook configurations.

Token Customization

Logto offers two distinct mechanisms for customizing JWT contents: Cloudflare Worker integration for global token transformation, and interaction-level JWT customizers for targeted payload modifications.

Cloudflare Worker JWT Rewriting

The Custom JWT extension point delegates token generation to a Cloudflare Worker URL you specify. Configuration is validated by customJwtWorkerConfigGuard in packages/schemas/src/types/system.ts (lines 188‑202).

import { customJwtWorkerConfigGuard } from 'logto/schemas';

const config = {
  cloudflareWorkerUrl: 'https://my-worker.example.com',
  secret: 'super‑secret',
};

customJwtWorkerConfigGuard.parse(config); // validates shape before saving

This approach intercepts the JWT before it reaches the client, allowing you to rewrite claims or augment payload data using external business logic.

Interaction-Level JWT Customizer

For per-interaction modifications (such as adding organization-specific claims), use the JWT customizer validated by customJwtFetcherGuard in packages/schemas/src/types/logto-config/jwt-customizer.ts (lines 180‑214). This entry point receives the full interaction context and returns modified token payloads.

User Interface Customization

Custom Sign-In UI Assets

You can replace Logto's default sign-in interface by uploading a zip archive of your own HTML, CSS, and JavaScript assets. The logto tunnel deploy CLI command handles packaging and deployment, implemented in packages/tunnel/src/commands/deploy/index.ts (lines 13‑34) with upload utilities in packages/tunnel/src/commands/deploy/utils.ts (lines 104‑179).

logto tunnel deploy \
  --endpoint https://api.logto.io \
  --access-token $TOKEN \
  --folder ./my-custom-ui

The CLI posts the archive to /api/sign-in-exp/default/custom-ui-assets and records the returned customUiAssetId for your tenant configuration.

Custom Content Security Policy (CSP)

When serving custom UI assets, you must whitelist external script and connection sources via the Custom CSP configuration. The customUiCsp object is defined and guarded in packages/toolkit/core-kit/src/custom-ui-csp.ts (lines 3‑12).

import { customUiCspGuard } from '@logto/toolkit';

const csp = {
  scriptSrc: ['https://cdn.jsdelivr.net'],
  connectSrc: ['https://api.logto.io'],
};

customUiCspGuard.parse(csp); // ensures only allowed directives pass validation

This prevents browser security errors while loading external resources in your custom interface.

Data Model Extensions

Custom Data Fields

Logto allows arbitrary JSON storage on users and applications through the customData field. The user schema in packages/schemas/src/types/user.ts (line 18) defines this field, which persists through the entire authentication lifecycle and appears in hook contexts.

await fetch(`${endpoint}/api/users/${userId}`, {
  method: 'PATCH',
  headers: { Authorization: `Bearer ${token}` },
  body: JSON.stringify({
    customData: {
      favoriteColor: 'blue',
      subscriptionPlan: 'pro',
    },
  }),
});

Custom Profile Fields

Beyond customData, you can define structured profile extensions via customProfileFields and customProfileFieldCatalog, configured in packages/schemas/src/types/sign-in-experience.ts (lines 57‑74). These fields appear in the admin console and can be validated against custom schemas.

Deployment Configuration

Custom Tenant IDs

For private-cloud deployments, Logto supports custom tenant identifiers using lowercase letters, numbers, and hyphens up to 21 characters. Validation uses customTenantIdRegEx and customTenantIdMaxLength from packages/toolkit/core-kit/src/regex.ts (lines 23‑30).

import { customTenantIdRegEx, customTenantIdMaxLength } from '@logto/toolkit';

function isValidTenantId(id: string) {
  return id.length <= customTenantIdMaxLength && customTenantIdRegEx.test(id);
}

Multiple Custom Domains

Enterprise deployments can enable multiple custom domains per tenant. The feature toggle and URL resolution logic reside in packages/shared/src/node/env/UrlSet.ts (lines 4‑18) and packages/shared/src/node/env/GlobalValues.ts (lines 157‑162).

import { GlobalValues } from '@logto/shared/node/env';

if (GlobalValues.isMultipleCustomDomainsEnabled) {
  // Logic to register additional hostnames per tenant
}

This allows organizations to serve authentication experiences from branded domains while maintaining a single Logto tenant backend.

Connector Customization

Connectors (OIDC, OAuth2, SAML, etc.) expose extension points for custom metadata, email templates, and internationalization strings. The metadata schema in packages/toolkit/connector-kit/src/types/metadata.ts (lines 56‑92) supports a customData field for connector-specific branding and configuration.

const myConnector = {
  id: 'my-oidc',
  type: 'oidc',
  metadata: {
    customData: { branding: 'dark', region: 'eu-west' },
  },
};

This lets connector developers embed arbitrary configuration data that the core Logto platform preserves and passes through during authentication flows.

Summary

  • Inline Hooks (PostFirstFactorVerification, PostSignIn) execute custom JavaScript at specific authentication lifecycle stages, defined in packages/schemas/src/types/logto-config/inline-hook.ts.
  • Custom JWT configurations support Cloudflare Worker integration (validated by customJwtWorkerConfigGuard in system.ts) and interaction-level customization (validated by customJwtFetcherGuard in jwt-customizer.ts).
  • Custom UI Assets deploy via the logto tunnel deploy CLI, with CSP whitelisting managed through customUiCspGuard in custom-ui-csp.ts.
  • Custom Data Fields store arbitrary JSON on users (user.ts line 18) and applications, while structured profile extensions use customProfileFields in sign-in-experience.ts.
  • Custom Tenant IDs follow regex patterns defined in regex.ts (lines 23‑30), supporting up to 21 characters.
  • Custom Domains rely on GlobalValues.isMultipleCustomDomainsEnabled and UrlSet configuration for enterprise multi-domain deployments.
  • Connector Metadata accepts custom data objects defined in metadata.ts (lines 56‑92) for template and branding customization.

Frequently Asked Questions

What is the difference between Inline Hooks and JWT Customizers?

Inline Hooks execute arbitrary JavaScript after specific authentication events (like PostSignIn) and are ideal for triggering external workflows or logging. JWT Customizers specifically modify token payloads either globally via Cloudflare Workers or per-interaction via the customizer guard, making them suited for claim augmentation. Hooks focus on side effects; customizers focus on token content.

How do I validate custom data before saving it to Logto?

Logto provides TypeScript guards for all extension points. Import customUiCspGuard for CSP validation, customJwtWorkerConfigGuard for JWT configuration, and inlineHookGuard for hook payloads. These guards are exported from their respective schema files (e.g., packages/toolkit/core-kit/src/custom-ui-csp.ts) and ensure data conforms to expected shapes before hitting the Management API.

Can I deploy a custom UI without modifying Logto's core code?

Yes. The logto tunnel deploy CLI command (source in packages/tunnel/src/commands/deploy/index.ts) uploads your static assets as a zip archive to Logto's cloud or your private instance. Logto serves these files instead of its default UI, and you configure CSP rules separately through the customUiCsp object—no core code changes required.

What are the limitations for custom tenant IDs?

Custom tenant IDs must match the regex pattern defined in packages/toolkit/core-kit/src/regex.ts (lines 23‑30), which restricts identifiers to lowercase letters, numbers, and hyphens with a maximum length of 21 characters. This ensures compatibility with Logto's internal routing and database naming conventions.

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 →