# How API Keys Are Managed and Used in Twenty CRM: A Complete Technical Guide

> Learn how Twenty CRM manages and uses API keys. Discover secure storage, JWT issuance, and role-based access control for robust API security. Get the complete technical guide.

- Repository: [Twenty/twenty](https://github.com/twentyhq/twenty)
- Tags: how-to-guide
- Published: 2026-03-27

---

**Twenty CRM stores API keys as hashed entities in the workspace database, issues them as signed JWTs with type `API_KEY`, and enforces role-based access through the `API_KEYS_AND_WEBHOOKS` permission flag.**

Twenty CRM treats API keys as first-class security credentials that grant programmatic access to the platform. The open-source repository `twentyhq/twenty` implements a comprehensive API key lifecycle through a dedicated module in the backend server (`twenty-server`). This article examines the technical architecture, authentication flow, and practical usage patterns based on the actual source code.

## Core Architecture of API Key Management

### Database Schema and Entity Design

At the foundation of the system lies the **`ApiKeyEntity`** defined in [`packages/twenty-server/src/engine/core-modules/api-key/api-key.entity.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/api-key/api-key.entity.ts). This TypeORM entity stores the key’s name, a hashed representation of the secret, the associated workspace ID, a linked role, and timestamps for auditing. The entity design ensures that raw secrets are never persisted in plain text; only irreversible hashes are retained in the database.

### JWT Token Structure and Signing

API keys in Twenty CRM are encoded as **JSON Web Tokens (JWTs)** with the specific type `JwtTokenTypeEnum.API_KEY`. The **`JwtWrapperService`** located in [`packages/twenty-server/src/engine/core-modules/jwt/services/jwt-wrapper.service.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/jwt/services/jwt-wrapper.service.ts) handles the cryptographic signing and verification. The JWT payload contains the key ID and workspace information, allowing stateless validation of the bearer’s identity without database lookups on every request.

### Permission Guarding

All API key operations are protected by the **`API_KEYS_AND_WEBHOOKS`** permission flag defined in [`packages/twenty-shared/src/constants/PermissionFlagType.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-shared/src/constants/PermissionFlagType.ts). This `PermissionFlagType` ensures that only workspace administrators or users with explicit webhook management rights can create, view, or revoke API keys. The permission check runs through the central authorization service before any controller or resolver method executes.

## API Key Lifecycle Management

### Generation and Creation

You can generate API keys through three interfaces: a CLI command, REST endpoints, or GraphQL mutations.

The **`GenerateApiKeyCommand`** in [`packages/twenty-server/src/engine/core-modules/api-key/commands/generate-api-key.command.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/api-key/commands/generate-api-key.command.ts) provides a server-side generation tool for development and CI pipelines:

```bash
npx nx run twenty-server:generate-api-key \
  --workspaceId <workspace-id> \
  --name "My Integration Key" \
  --roleId <role-id>

```

The command invokes `ApiKeyService.create()`, which generates a cryptographically random secret, hashes it for storage, and signs a JWT. The raw secret prints to stdout exactly once and must be stored securely by the operator.

Alternatively, the **`ApiKeyController`** ([`packages/twenty-server/src/engine/core-modules/api-key/controllers/api-key.controller.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/api-key/controllers/api-key.controller.ts)) exposes REST endpoints at `/api/api-keys`, while the **`ApiKeyResolver`** ([`packages/twenty-server/src/engine/core-modules/api-key/api-key.resolver.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/api-key/api-key.resolver.ts)) handles GraphQL mutations. Both interfaces enforce the `API_KEYS_AND_WEBHOOKS` permission before delegating to `ApiKeyService`.

### Rotation and Updates

Key rotation is handled through **`UpdateApiKeyInput`**. Administrators can rename keys or re-assign roles, and the system supports full secret rotation. When rotating, the service generates a new secret hash, invalidates previous JWTs by updating the entity’s state, and issues a new bearer token. This ensures that compromised credentials can be cycled without deleting the key’s metadata or historical audit trail.

### Revocation

Revocation occurs through the **`RevokeApiKeyInput`** mutation or corresponding REST endpoint. The service sets a `revokedAt` timestamp on the `ApiKeyEntity`. The **`JwtAuthStrategy`** checks this timestamp during validation; if present, the token is rejected immediately. This approach provides instantaneous revocation without requiring JWT blacklists or distributed cache invalidation.

## Authentication Flow and Role Resolution

When a client sends a request with `Authorization: Bearer <token>`, the **`JwtAuthStrategy`** in [`packages/twenty-server/src/engine/core-modules/auth/strategies/jwt.auth.strategy.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/auth/strategies/jwt.auth.strategy.ts) executes. The strategy inspects the JWT’s `type` field. Upon encountering `JwtTokenTypeEnum.API_KEY`, it:

1. Validates the JWT signature and expiration
2. Loads the associated role via **`WorkspaceApiKeyRoleMapCacheService`** ([`packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service.ts))
3. Constructs an `authContext` object containing the key ID, workspace ID, and role permissions

This context then drives the GraphQL/REST authorization layer, ensuring the API key can only access metadata objects and actions permitted by its assigned role.

## Using API Keys in Practice

### REST API Authentication

Include the JWT as a Bearer token in the Authorization header:

```http
GET /api/users HTTP/1.1
Host: api.twenty.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

```

The server validates the token through `JwtWrapperService.verify()` and applies role-based filters to the response.

### GraphQL Creation Mutation

Create keys programmatically via the GraphQL API:

```graphql
mutation CreateApiKey($input: CreateApiKeyInput!) {
  createApiKey(input: $input) {
    id
    name
    role {
      id
    }
    token   # raw secret – only returned once

  }
}

```

Variables:

```json
{
  "input": {
    "workspaceId": "123e4567-e89b-12d3-a456-426614174000",
    "name": "Automation Bot",
    "roleId": "b1c2d3e4-f5a6-78b9-c0d1-ef23456789ab"
  }
}

```

The resolver delegates to `ApiKeyService.create()`, persisting the entity and returning the signed JWT.

### Revocation via GraphQL

Invalidate a key immediately:

```graphql
mutation RevokeApiKey($id: ID!) {
  revokeApiKey(id: $id) {
    success
  }
}

```

## Internal Service Integration

Twenty CRM uses API keys for machine-to-machine authentication between internal services. The system expects an environment variable named **`TWENTY_API_KEY`**, exported as **`DEFAULT_API_KEY_NAME`** in [`packages/twenty-shared/src/application/constants/DefaultApiKeyName.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-shared/src/application/constants/DefaultApiKeyName.ts).

The **[`logic-function-executor.service.ts`](https://github.com/twentyhq/twenty/blob/main/logic-function-executor.service.ts)** ([`packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts)) demonstrates this pattern, reading the default key to impersonate an application client when executing server-side logic functions. This allows internal microservices to authenticate against the public API using the same JWT mechanism as external clients.

## Summary

- **Storage**: API keys are stored as `ApiKeyEntity` objects with hashed secrets, never plain text, in the workspace database.
- **Token Format**: Keys are issued as JWTs with type `JwtTokenTypeEnum.API_KEY` signed by `JwtWrapperService`.
- **Permissions**: All management operations require the `API_KEYS_AND_WEBHOOKS` permission flag.
- **Role Binding**: Each key maps to a role via `WorkspaceApiKeyRoleMapCacheService`, determining accessible resources.
- **Lifecycle**: Create via `GenerateApiKeyCommand`, REST, or GraphQL; rotate through `UpdateApiKeyInput`; revoke via `RevokeApiKeyInput`.
- **Authentication**: Send the JWT as a Bearer token; `JwtAuthStrategy` validates and builds an `authContext` with role permissions.
- **Internal Usage**: Services use the `TWENTY_API_KEY` environment variable for machine-to-machine authentication.

## Frequently Asked Questions

### How are API keys stored in Twenty CRM?

API keys are stored as `ApiKeyEntity` records in the workspace database using TypeORM. The entity stores a hashed version of the secret using cryptographic hashing, along with the key name, workspace ID, associated role ID, and timestamps. Raw secrets are only transmitted once during creation and are never persisted in reversible form.

### What permission is required to manage API keys?

All API key creation, rotation, and revocation actions require the **`API_KEYS_AND_WEBHOOKS`** permission flag. This constant is defined in `PermissionFlagType` and enforced by the permissions service before any controller or resolver method executes. Only workspace administrators or users explicitly granted webhook management rights can perform these operations.

### How do I authenticate API requests using a Twenty CRM API key?

Authenticate by sending the JWT token as a Bearer token in the Authorization header: `Authorization: Bearer <jwt>`. The system accepts these tokens on both REST endpoints (`/api/*`) and GraphQL endpoints. The `JwtAuthStrategy` validates the token, confirms it has type `API_KEY`, and loads the associated role permissions into the request context.

### Can API keys be rotated without deleting them?

Yes. The `UpdateApiKeyInput` mutation and corresponding REST endpoints support key rotation. When rotating, the `ApiKeyService` generates a new cryptographically random secret, updates the stored hash, and issues a new JWT. Previous JWTs are invalidated immediately because they no longer match the stored hash, while the key’s ID, name, and audit history remain intact.