packages/twenty-docs/developers/extend/oauth.mdx
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.
| Scenario | Auth Method |
|---|---|
| Internal scripts, automation | API Key |
| External app acting on behalf of a user | OAuth — Authorization Code |
| Server-to-server, no user context | OAuth — Client Credentials |
| Twenty App with UI extensions | Apps (OAuth is handled automatically) |
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"]
}
| Scope | Access |
|---|---|
api | Full read/write access to the Core and Metadata APIs |
profile | Read the authenticated user's profile information |
Request scopes as a space-separated string: scope=api profile
Use this flow when your app acts on behalf of a Twenty user.
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
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your registered client ID |
response_type | Yes | Must be code |
redirect_uri | Yes | Must match a registered redirect URI |
scope | No | Space-separated scopes (defaults to api) |
state | Recommended | Random string to prevent CSRF attacks |
code_challenge | Recommended | PKCE challenge (SHA-256 hash of verifier, base64url-encoded) |
code_challenge_method | Recommended | Must be S256 when using PKCE |
The user sees a consent screen and approves or denies access.
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.
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..."
}
GET /rest/companies
Authorization: Bearer ACCESS_TOKEN
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
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.
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.
| Endpoint | Purpose |
|---|---|
/.well-known/oauth-authorization-server | Server metadata discovery |
/oauth/register | Dynamic client registration |
/oauth/authorize | User authorization |
/oauth/token | Token exchange and refresh |
| Environment | Base URL |
|---|---|
| Cloud | https://api.twenty.com |
| Self-Hosted | https://{your-domain} |
| API Keys | OAuth | |
|---|---|---|
| Setup | Generate in Settings | Register a client, implement flow |
| User context | None (workspace-level) | Specific user's permissions |
| Best for | Scripts, internal tools | External apps, multi-user integrations |
| Token rotation | Manual | Automatic via refresh tokens |
| Scoped access | Full API access | Granular via scopes |