How API Keys Are Managed and Used in Twenty CRM: A Complete Technical Guide
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. 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 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. 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 provides a server-side generation tool for development and CI pipelines:
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) exposes REST endpoints at /api/api-keys, while the ApiKeyResolver (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 executes. The strategy inspects the JWT’s type field. Upon encountering JwtTokenTypeEnum.API_KEY, it:
- Validates the JWT signature and expiration
- Loads the associated role via
WorkspaceApiKeyRoleMapCacheService(packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service.ts) - Constructs an
authContextobject 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:
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:
mutation CreateApiKey($input: CreateApiKeyInput!) {
createApiKey(input: $input) {
id
name
role {
id
}
token # raw secret – only returned once
}
}
Variables:
{
"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:
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.
The logic-function-executor.service.ts (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
ApiKeyEntityobjects with hashed secrets, never plain text, in the workspace database. - Token Format: Keys are issued as JWTs with type
JwtTokenTypeEnum.API_KEYsigned byJwtWrapperService. - Permissions: All management operations require the
API_KEYS_AND_WEBHOOKSpermission flag. - Role Binding: Each key maps to a role via
WorkspaceApiKeyRoleMapCacheService, determining accessible resources. - Lifecycle: Create via
GenerateApiKeyCommand, REST, or GraphQL; rotate throughUpdateApiKeyInput; revoke viaRevokeApiKeyInput. - Authentication: Send the JWT as a Bearer token;
JwtAuthStrategyvalidates and builds anauthContextwith role permissions. - Internal Usage: Services use the
TWENTY_API_KEYenvironment 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.
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 →