OAuth 2.1
For apps acting on behalf of a user (Zapier, n8n, chat connectors): authorization code with PKCE, refresh tokens, consent with organization choice. For server-to-server the API key remains the simpler way.
When OAuth, when keys
API keys (capi_…) belong to an organization and suit scripts and servers. OAuth tokens belong to a user who grants one organization in the consent screen — so end users connect their own claritos organization to a third-party app without copying keys. Both ways use the same scopes and endpoints.
Authorization code + PKCE
The client sends the user to authorize (PKCE is mandatory, S256), receives a code at its redirect URI after consent and exchanges it at the token endpoint for an access token (1 hour) and a refresh token (30 days). Confidential clients send their client_secret; public clients only the code_verifier.
GET https://www.claritos.io/api/auth/oauth2/authorize
?response_type=code
&client_id=CLIENT_ID
&redirect_uri=https://app.example.com/callback
&scope=openid%20offline_access%20contacts:read%20invoices:write
&state=RANDOM
&code_challenge=BASE64URL(SHA256(code_verifier))
&code_challenge_method=S256curl -X POST https://www.claritos.io/api/auth/oauth2/token \
-d grant_type=authorization_code \
-d code=CODE_FROM_CALLBACK \
-d redirect_uri=https://app.example.com/callback \
-d client_id=CLIENT_ID -d client_secret=CLIENT_SECRET \
-d code_verifier=CODE_VERIFIER{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "…",
"scope": "openid offline_access contacts:read invoices:write"
}Consent with organization choice
The user sees the client and the requested permissions and chooses the organization the access applies to. Exactly one per connection; permissions apply only as far as the user’s role in the organization allows (membership is checked on every call). Clients-data scopes additionally need the organization’s enablement. Since 1.26.0 the user can deselect individual permissions in the consent; access applies only to the selected scopes, clients-data scopes are deselected by default. Users see their grants in the profile under “Connected apps” and can revoke them there at any time.
Calling the API
The access token is sent like a key as a Bearer token. GET /me shows organization, scopes and limits of the token.
curl https://www.claritos.io/api/v1/me -H "Authorization: Bearer ACCESS_TOKEN"Refreshing tokens
When the access token expires, the token endpoint returns a new pair with grant_type=refresh_token. Refresh tokens are rotated.
curl -X POST https://www.claritos.io/api/auth/oauth2/token \
-d grant_type=refresh_token -d refresh_token=REFRESH_TOKEN \
-d client_id=CLIENT_ID -d client_secret=CLIENT_SECRETDiscovery
Metadata per RFC 8414 (authorization server) and RFC 9728 (protected resource) live at the root; the OpenID configuration additionally under the auth path. Clients supporting discovery (MCP connectors) only need the base URL.
GET https://www.claritos.io/.well-known/oauth-authorization-server
GET https://www.claritos.io/.well-known/oauth-protected-resource
GET https://www.claritos.io/api/auth/.well-known/openid-configurationDynamic client registration
Clients can register themselves (RFC 7591) — this is how claude.ai, ChatGPT and other MCP clients connect without manual setup. Registered clients appear in the system area and can be disabled there.
curl -X POST https://www.claritos.io/api/auth/oauth2/register \
-H "Content-Type: application/json" \
-d '{ "client_name": "My MCP client", "redirect_uris": ["https://client.example.com/cb"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code","refresh_token"] }'Zapier, n8n, Make
Create a client in the system area (enter the platform’s redirect URI), store client_id/client_secret there, authorization URL /api/auth/oauth2/authorize, token URL /api/auth/oauth2/token, scopes as needed (e.g. contacts:write invoices:read). Enable PKCE if the platform offers it. Per-platform setup see the “Webhooks” guide → Platforms.