Files
twenty/packages/twenty-sdk
Félix Malfait 95a35f8a1d Implement OAuth 2.0 Dynamic Client Registration (RFC 7591) (#18608)
## Summary
This PR implements OAuth 2.0 Dynamic Client Registration (RFC 7591) and
OAuth 2.0 Protected Resource Metadata (RFC 9728) support, enabling
third-party applications to dynamically register as OAuth clients
without manual configuration.

## Key Changes

### OAuth Dynamic Client Registration
- **New Controller**: `OAuthRegistrationController` at `POST
/oauth/register` endpoint
  - Validates client metadata according to RFC 7591 specifications
  - Enforces PKCE-only public client model (no client secrets)
- Supports only `authorization_code` grant type and `code` response type
  - Rate limits registrations to 10 per hour per IP address
  - Returns `client_id` and registration metadata in response

- **Input Validation**: `OAuthRegisterInput` DTO with constraints on:
  - Client name (max 256 chars)
  - Redirect URIs (max 20, validated for security)
  - Grant types, response types, scopes, and auth methods
  - Logo and client URIs (max 2048 chars)

- **Discovery Endpoint Update**: Added `registration_endpoint` to OAuth
discovery metadata

### Stale Registration Cleanup
- **Cleanup Service**: Automatically removes OAuth-only registrations
older than 30 days that have no active installations
- **Cron Job**: Runs daily at 02:30 AM UTC with batch processing (100
records per batch)
- **CLI Command**: `cron:stale-registration-cleanup` to manually trigger
cleanup

### MCP (Model Context Protocol) Authentication
- **New Guard**: `McpAuthGuard` implements RFC 9728 compliance
  - Wraps JWT authentication with proper error responses
- Returns `WWW-Authenticate` header with protected resource metadata URL
on 401
  - Enables OAuth-protected MCP endpoints

### Protected Resource Metadata
- **New Endpoint**: `GET /.well-known/oauth-protected-resource` (RFC
9728)
  - Advertises MCP resource as OAuth-protected
  - Lists supported scopes and bearer token methods
  - Enables OAuth clients to discover authorization requirements

### Application Registration Updates
- **New Source Type**: `OAUTH_ONLY` enum value for OAuth-only
registrations
- **Install Service**: Skips artifact installation for OAuth-only apps
(no code artifacts)

### Frontend Updates
- **Authorization Page**: Support both snake_case (standard OAuth) and
camelCase (legacy) query parameters
  - `client_id` / `clientId`
  - `code_challenge` / `codeChallenge`
  - `redirect_uri` / `redirectUrl`

## Implementation Details

- **Rate Limiting**: Uses token bucket algorithm with 10 registrations
per 3,600,000ms window per IP
- **Scope Validation**: Requested scopes are capped to allowed OAuth
scopes; defaults to all scopes if not specified
- **Redirect URI Validation**: Uses existing `validateRedirectUri`
utility for security
- **Cache Headers**: Registration responses include `Cache-Control:
no-store` and `Pragma: no-cache`
- **Batch Processing**: Cleanup operations process 100 records at a time
to avoid memory issues
- **Grace Period**: 30-day grace period before cleanup to allow time for
client activation

https://claude.ai/code/session_01PxcuWFFRuXMASMaMGTLYk2

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@twenty.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-03-16 09:42:28 +01:00
..
2026-03-09 15:32:13 +00:00
2026-03-09 15:32:13 +00:00
2026-03-13 11:06:14 +00:00

Twenty logo

Twenty SDK

NPM version License Join the community on Discord

A CLI and SDK to develop, build, and publish applications that extend Twenty CRM.

  • Typed GraphQL clients: CoreApiClient (auto-generated per app for workspace data) and MetadataApiClient (pre-built with the SDK for workspace configuration & file uploads)
  • Builtin CLI for auth, dev mode (watch & sync), uninstall, and function management
  • Works great with the scaffolder: create-twenty-app

Documentation

See Twenty application documentation https://docs.twenty.com/developers/extend/capabilities/apps

Prerequisites

Installation

npm install twenty-sdk
# or
yarn add twenty-sdk

Usage

Usage: twenty [options] [command]

CLI for Twenty application development

Options:
  --workspace <name>   Use a specific workspace configuration (default: "default")
  -V, --version        output the version number
  -h, --help           display help for command

Commands:
  auth:login           Authenticate with Twenty
  auth:logout          Remove authentication credentials
  auth:status          Check authentication status
  auth:switch          Switch the default workspace
  auth:list            List all configured workspaces
  app:dev              Watch and sync local application changes
  app:build            Build, sync, and generate API client
  app:publish          Build and publish to npm or a Twenty server
  app:typecheck        Run TypeScript type checking on the application
  app:uninstall        Uninstall application from Twenty
  entity:add           Add a new entity to your application
  function:logs        Watch application function logs
  function:execute     Execute a logic function with a JSON payload
  help [command]       display help for command

In a scaffolded project (via create-twenty-app), use yarn twenty <command> instead of calling twenty directly. For example: yarn twenty help, yarn twenty app:dev, etc.

Global Options

  • --workspace <name>: Use a specific workspace configuration profile. Defaults to default. See Configuration for details.

Commands

Auth

Authenticate the CLI against your Twenty workspace.

  • twenty auth:login — Authenticate with Twenty.

    • Options:
      • --api-key <key>: API key for authentication.
      • --api-url <url>: Twenty API URL (defaults to your current profile's value or http://localhost:3000).
    • Behavior: Prompts for any missing values, persists them to the active workspace profile, and validates the credentials.
  • twenty auth:logout — Remove authentication credentials for the active workspace profile.

  • twenty auth:status — Print the current authentication status (API URL, masked API key, validity).

  • twenty auth:list — List all configured workspaces.

    • Behavior: Displays all available workspaces with their authentication status and API URLs. Shows which workspace is the current default.
  • twenty auth:switch [workspace] — Switch the default workspace for authentication.

    • Arguments:
      • workspace (optional): Name of the workspace to switch to. If omitted, shows an interactive selection.
    • Behavior: Sets the specified workspace as the default, so subsequent commands use it without needing --workspace.

Examples:

# Login interactively (recommended)
twenty auth:login

# Provide values in flags
twenty auth:login --api-key $TWENTY_API_KEY --api-url https://api.twenty.com

# Login interactively for a specific workspace profile
twenty auth:login --workspace my-custom-workspace

# Check status
twenty auth:status

# Logout current profile
twenty auth:logout

# List all configured workspaces
twenty auth:list

# Switch default workspace interactively
twenty auth:switch

# Switch to a specific workspace
twenty auth:switch production

App

Application development commands.

  • twenty app:dev [appPath] — Start development mode: watch and sync local application changes.

    • Behavior: Builds your application (functions and front components), computes the manifest, syncs everything to your workspace, then watches the directory for changes and re-syncs automatically. Displays an interactive UI showing build and sync status in real time. Press Ctrl+C to stop.
  • twenty app:build [appPath] — Build the application, sync to the server, generate the typed API client, then rebuild with the real client.

    • Options:
      • --tarball: Also pack the output into a .tgz tarball.
  • twenty app:publish [appPath] — Build and publish the application.

    • Default (no flags): builds and runs npm publish on the output directory.
    • Options:
      • --server <url>: Publish to a Twenty server instead of npm (builds tarball, uploads, and installs).
      • --token <token>: Auth token for the server.
      • --tag <tag>: npm dist-tag (e.g. beta, next).
  • twenty app:typecheck [appPath] — Run TypeScript type checking on the application (runs tsc --noEmit). Exits with code 1 if type errors are found.

  • twenty app:uninstall [appPath] — Uninstall the application from the current workspace.

Entity

  • twenty entity:add [entityType] — Add a new entity to your application.
    • Arguments:
      • entityType: one of object, field, function, front-component, role, view, navigation-menu-item, or skill. If omitted, an interactive prompt is shown.
    • Options:
      • --path <path>: The path where the entity file should be created (relative to the current directory).
    • Behavior:
      • object: prompts for singular/plural names and labels, then creates a *.object.ts definition file.
      • field: prompts for name, label, type, and target object, then creates a *.field.ts definition file.
      • function: prompts for a name and scaffolds a *.function.ts logic function file.
      • front-component: prompts for a name and scaffolds a *.front-component.tsx file.
      • role: prompts for a name and scaffolds a *.role.ts role definition file.
      • view: prompts for a name and target object, then creates a *.view.ts definition file.
      • navigation-menu-item: prompts for a name and scaffolds a *.navigation-menu-item.ts file.
      • skill: prompts for a name and scaffolds a *.skill.ts skill definition file.

Function

  • twenty function:logs [appPath] — Stream application function logs.

    • Options:
      • -u, --functionUniversalIdentifier <id>: Only show logs for a specific function universal ID.
      • -n, --functionName <name>: Only show logs for a specific function name.
  • twenty function:execute [appPath] — Execute a logic function with a JSON payload.

    • Options:
      • --preInstall: Execute the pre-install logic function defined in the application manifest (required if --postInstall, -n, and -u not provided).
      • --postInstall: Execute the post-install logic function defined in the application manifest (required if --preInstall, -n, and -u not provided).
      • -n, --functionName <name>: Name of the function to execute (required if --postInstall and -u not provided).
      • -u, --functionUniversalIdentifier <id>: Universal ID of the function to execute (required if --postInstall and -n not provided).
      • -p, --payload <payload>: JSON payload to send to the function (default: {}).

Examples:

# Start dev mode (watch, build, and sync)
twenty app:dev

# Start dev mode with a custom workspace profile
twenty app:dev --workspace my-custom-workspace

# Type check the application
twenty app:typecheck

# Add a new entity interactively
twenty entity:add

# Add a new function
twenty entity:add function

# Add a new front component
twenty entity:add front-component

# Add a new view
twenty entity:add view

# Add a new navigation menu item
twenty entity:add navigation-menu-item

# Add a new skill
twenty entity:add skill

# Build the app (output in .twenty/output/)
twenty app:build

# Build and create a tarball
twenty app:build --tarball

# Publish to npm
twenty app:publish

# Publish with a dist-tag
twenty app:publish --tag beta

# Publish directly to a Twenty server (builds, uploads, and installs)
twenty app:publish --server https://app.twenty.com

# Uninstall the app from the workspace
twenty app:uninstall

# Watch all function logs
twenty function:logs

# Watch logs for a specific function by name
twenty function:logs -n my-function

# Execute a function by name (with empty payload)
twenty function:execute -n my-function

# Execute a function with a JSON payload
twenty function:execute -n my-function -p '{"name": "test"}'

# Execute a function by universal identifier
twenty function:execute -u e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf -p '{"key": "value"}'

# Execute the pre-install function
twenty function:execute --preInstall

# Execute the post-install function
twenty function:execute --postInstall

Configuration

The CLI stores configuration per user in a JSON file:

  • Location: ~/.twenty/config.json
  • Structure: Profiles keyed by workspace name. The active profile is selected with --workspace <name> or by the defaultWorkspace setting.

Example configuration file:

{
  "defaultWorkspace": "prod",
  "profiles": {
    "default": {
      "apiUrl": "http://localhost:3000",
      "apiKey": "<your-api-key>"
    },
    "prod": {
      "apiUrl": "https://api.twenty.com",
      "apiKey": "<your-api-key>"
    }
  }
}

Notes:

  • If a profile is missing, apiUrl defaults to http://localhost:3000 until set.
  • twenty auth:login writes the apiUrl and apiKey for the active workspace profile.
  • twenty auth:login --workspace custom-workspace writes the apiUrl and apiKey for a custom custom-workspace profile.
  • twenty auth:switch sets the defaultWorkspace field, which is used when --workspace is not specified.
  • twenty auth:list shows all configured workspaces and their authentication status.

Troubleshooting

  • Auth errors: run twenty auth:login again and ensure the API key has the required permissions.
  • Typings out of date: restart twenty app:dev to refresh the client and types.
  • Not seeing changes in dev: make sure dev mode is running (twenty app:dev).

Contributing

Development Setup

To contribute to the twenty-sdk package, clone the repository and install dependencies:

git clone https://github.com/twentyhq/twenty.git
cd twenty
yarn install

Development Mode

Run the SDK build in watch mode to automatically rebuild on file changes:

npx nx run twenty-sdk:dev

This will watch for changes and rebuild the dist folder automatically.

Production Build

Build the SDK for production:

npx nx run twenty-sdk:build

Running the CLI Locally

After building, you can run the CLI directly:

npx nx run twenty-sdk:start -- <command>
# Example: npx nx run twenty-sdk:start -- auth:status

Or run the built CLI directly:

node packages/twenty-sdk/dist/cli.cjs <command>

Resources