Skip to main content
Twenty implements OAuth 2.0 with authorization code + PKCE for user-facing apps and client credentials for server-to-server access. Clients are registered dynamically via RFC 7591 — no manual setup in a dashboard.

When to Use OAuth

ScenarioAuth Method
Internal scripts, automationAPI Key
External app acting on behalf of a userOAuth — Authorization Code
Server-to-server, no user contextOAuth — Client Credentials
Twenty App with UI extensionsApps (OAuth is handled automatically)

Register a Client

Twenty supports dynamic client registration per RFC 7591. No manual setup needed — register programmatically:
POST /oauth/register
Content-Type: application/json

{
  "client_name": "My Integration",
  "redirect_uris": ["https://myapp.com/callback"],
  "grant_types": ["authorization_code"],
  "token_endpoint_auth_method": "client_secret_post"
}
Response:
{
  "client_id": "abc123",
  "client_secret": "secret456",
  "client_name": "My Integration",
  "redirect_uris": ["https://myapp.com/callback"]
}
Store the client_secret securely — it cannot be retrieved later.

Scopes

ScopeAccess
apiFull read/write access to the Core and Metadata APIs
profileRead the authenticated user’s profile information
Request scopes as a space-separated string: scope=api profile

Authorization Code Flow

Use this flow when your app acts on behalf of a Twenty user.

1. Redirect the user to authorize

GET /oauth/authorize?
  client_id=YOUR_CLIENT_ID&
  response_type=code&
  redirect_uri=https://myapp.com/callback&
  scope=api&
  state=random_state_value&
  code_challenge=CHALLENGE&
  code_challenge_method=S256
ParameterRequiredDescription
client_idYesYour registered client ID
response_typeYesMust be code
redirect_uriYesMust match a registered redirect URI
scopeNoSpace-separated scopes (defaults to api)
stateRecommendedRandom string to prevent CSRF attacks
code_challengeRecommendedPKCE challenge (SHA-256 hash of verifier, base64url-encoded)
code_challenge_methodRecommendedMust be S256 when using PKCE
The user sees a consent screen and approves or denies access.

2. Handle the callback

After authorization, Twenty redirects back to your redirect_uri:
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
Verify that state matches what you sent.

3. Exchange the code for tokens

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=https://myapp.com/callback&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
code_verifier=YOUR_PKCE_VERIFIER
Response:
{
  "access_token": "eyJhbG...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "dGhpcyBpcyBh..."
}

4. Use the access token

GET /rest/companies
Authorization: Bearer ACCESS_TOKEN

5. Refresh when expired

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&
refresh_token=YOUR_REFRESH_TOKEN&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET

Client Credentials Flow

For server-to-server integrations with no user interaction:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
scope=api
The returned token has workspace-level access, not tied to any specific user.

Server Discovery

Twenty publishes its OAuth configuration at a standard discovery endpoint:
GET /.well-known/oauth-authorization-server
This returns all endpoints, supported grant types, scopes, and capabilities — useful for building generic OAuth clients.

API Endpoints Summary

EndpointPurpose
/.well-known/oauth-authorization-serverServer metadata discovery
/oauth/registerDynamic client registration
/oauth/authorizeUser authorization
/oauth/tokenToken exchange and refresh
EnvironmentBase URL
Cloudhttps://api.twenty.com
Self-Hostedhttps://{your-domain}

OAuth vs API Keys

API KeysOAuth
SetupGenerate in SettingsRegister a client, implement flow
User contextNone (workspace-level)Specific user’s permissions
Best forScripts, internal toolsExternal apps, multi-user integrations
Token rotationManualAutomatic via refresh tokens
Scoped accessFull API accessGranular via scopes