How to Extend Logto's Functionality: A Developer's Guide to Custom Connectors and Inline Hooks

You can extend Logto's functionality by creating custom connectors (self-contained Node.js packages for identity/email/SMS providers) or implementing inline hooks (JavaScript functions that execute during authentication events) without modifying core code.

Logto is architected as a modular, extensible platform where the core runtime remains stable while integration points allow customization. The primary extension mechanisms reside in packages/connectors for third-party service integrations and packages/schemas along with packages/core/src/libraries/inline-hook.ts for runtime customization logic. These extension points let you add new identity providers, messaging services, or custom validation logic while maintaining compatibility with upstream updates.

Understanding Logto's Extension Architecture

Logto separates concerns between its immutable core and pluggable extensions. The core runtime lives in packages/core and handles authentication flows, session management, and user storage. Connectors are self-contained Node.js packages that bridge Logto to external services like OAuth providers or SMS gateways. Inline hooks are JavaScript functions executed in a sandboxed VM during specific authentication lifecycle events, allowing you to modify user objects or enforce custom policies.

The key source files defining these extension contracts include packages/toolkit/connector-kit/src/index.ts (providing typed helpers like ConnectorError and jsonGuard), packages/schemas/src/types/logto-config/inline-hook.ts (Zod schemas for hook payloads), and packages/core/src/libraries/inline-hook.ts (the runtime execution engine).

Creating Custom Connectors

Connectors are the primary way to extend Logto's functionality for identity verification and messaging. Each connector is a standalone package under packages/connectors/ that implements a consistent interface.

Connector Structure and Requirements

Every connector follows a standardized template synchronized from templates/package.json via the pnpm:devPreinstall script. Required files include:

  • package.json with "main": "src/index.ts" pointing to your entry point
  • Implementation of provider-specific functions like sendVerificationCode or verifyCode
  • Error handling using ConnectorError and ConnectorErrorCodes from @logto/connector-kit

Implementation Steps

  1. Create the package directory under packages/connectors/ (e.g., connector-custom-sms).

  2. Initialize from template by running pnpm i, which syncs boilerplate fields from the central template.

  3. Implement required functions in src/index.ts. For an SMS connector, you must export sendVerificationCode:

// packages/connectors/connector-custom-sms/src/index.ts
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
import ky from 'ky';

export const sendVerificationCode = async (phone: string, code: string) => {
  const res = await ky.post('https://api.custom-sms.com/send', {
    json: { to: phone, message: `Your code: ${code}` },
  }).json();

  if (res.status !== 'ok') {
    throw new ConnectorError(ConnectorErrorCodes.General, 'SMS delivery failed');
  }
};
  1. Build the package using pnpm build to compile TypeScript.

  2. Register via Console UI by navigating to Tenant → Connectors → Add Connector, or use the Management API as shown below.

Implementing Inline Hooks

Inline hooks let you extend Logto's functionality by injecting custom JavaScript into authentication flows without deploying new packages. These scripts execute in a sandboxed VM during specific events like post-first-factor verification or post-sign-in.

Hook Types and Payloads

The available hook types are defined in packages/schemas/src/types/logto-config/inline-hook.ts using Zod schemas. Common triggers include:

  • inlineHook.postFirstFactorVerification: Runs after password/OTP verification
  • inlineHook.postSignIn: Executes after successful authentication

Each hook receives a typed payload containing the user object, identifiers, and verification status.

Writing and Deploying Hook Scripts

Create a JavaScript file that exports a runInlineHook function receiving the event payload:

// scripts/post-signin-add-claim.js
async function runInlineHook(payload) {
  const { user } = payload; // user follows HookUser type from schemas
  
  return {
    action: 'updateUser',
    user: { customData: { welcomeBack: true } },
  };
}

module.exports = { runInlineHook };

Deploy the hook using the Admin API endpoint defined in packages/core/src/routes/logto-config/inline-hook.ts:

curl -X POST https://localhost:3002/api/connector/inline-hooks \
  -H "Authorization: Bearer <admin-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "hookType": "inlineHook.postFirstFactorVerification",
    "script": "$(cat scripts/post-first-factor.js)",
    "enabled": true,
    "onExecutionError": "block"
  }'

The InlineHookLibrary in packages/core/src/libraries/inline-hook.ts loads your script into a VM and executes it during the specified authentication phase. If onExecutionError is set to "block", authentication fails when the hook throws an error.

Advanced Extension: Adding Custom Hook Events

For deeper integration requiring new event types, you can extend the core by modifying packages/schemas/src/foundations/jsonb-types/hooks.ts to add new HookEvent constants. Update the database schema in packages/schemas/tables/hooks.sql and implement handling in packages/core/src/libraries/inline-hook.ts. This approach requires maintaining a forked version of Logto and migrating database changes.

Programmatic Connector Registration

You can automate connector deployment using the Logto Management SDK instead of the Console UI:

import { ManagementApi } from '@logto/sdk';

const api = new ManagementApi('https://localhost:3002', '<admin-token>');
await api.connectors.create({
  connectorId: 'custom-sms',
  config: { apiKey: 'xxxx' },
});

This method is particularly useful for infrastructure-as-code setups or multi-tenant environments where you need to extend Logto's functionality across multiple instances.

Summary

  • Custom connectors are self-contained Node.js packages in packages/connectors/ that implement standardized functions for external service integration.
  • Inline hooks are JavaScript functions uploaded via the Admin API (packages/core/src/routes/logto-config/inline-hook.ts) that execute during specific authentication events.
  • The connector SDK (packages/toolkit/connector-kit/src/index.ts) provides typed utilities like ConnectorError for robust error handling.
  • Registration occurs through the Console UI or Management API after building connectors with pnpm build.
  • Core modification requires editing schema files in packages/schemas and runtime logic in packages/core/src/libraries/inline-hook.ts for entirely new event types.

Frequently Asked Questions

What is the difference between a connector and an inline hook?

A connector is a permanent package integration for external services like email providers or social identity platforms, requiring build and deployment steps. An inline hook is a runtime JavaScript snippet uploaded through the API that executes during specific authentication events to modify user data or enforce custom logic without redeploying Logto.

Can I extend Logto's functionality without forking the repository?

Yes. You can extend Logto's functionality using custom connectors (created as separate packages under packages/connectors/ and built with pnpm build) or inline hooks (uploaded via the Admin API). Both methods work with the standard Logto distribution and do not require modifying core source files.

How do I handle errors in custom connectors?

Import ConnectorError and ConnectorErrorCodes from @logto/connector-kit and throw specific errors in your implementation functions. For example: throw new ConnectorError(ConnectorErrorCodes.General, 'SMS delivery failed'). These errors propagate through Logto's core and display appropriate messages to end users.

Where are inline hook scripts stored and executed?

Inline hook scripts are stored in the Logto database and executed by the InlineHookLibrary class in packages/core/src/libraries/inline-hook.ts. The library creates a sandboxed VM context for each execution, enforces payload schemas defined in packages/schemas/src/types/logto-config/inline-hook.ts, and handles the return values to determine whether to proceed with or block the authentication flow.

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 →