KLCTDevelopers

OAuth 2.1

View as Markdown

Use OAuth when your product connects to your customers' KLCT accounts. It is the standard authorization code flow with PKCE. The customer signs in to KLCT, picks the account to connect and ticks the scopes they allow. You never see their password.

Get a client

Clients are pre-registered; there is no open self-registration. Ask KLCT to register your product with:

  • a name shown on the consent screen,
  • one or more redirect URIs (HTTPS, or a loopback address for local testing; exact match, or a wildcard host such as https://*.example.com/callback),
  • the scopes you may ever request.

You receive a client_id and a client_secret.

1. Send the customer to KLCT

GET https://app.klctai.com/oauth/platform/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.example/klct/callback
  &scope=contacts:read%20tickets:read%20tickets:write
  &state=RANDOM_STATE
  &code_challenge=BASE64URL_SHA256_OF_VERIFIER
  &code_challenge_method=S256

PKCE with S256 is required. Generate a random code_verifier (43 to 128 URL-safe characters) per attempt, keep it server-side, and send its SHA-256 hash, base64url-encoded, as code_challenge. Always check that the state you get back matches the one you sent.

KLCT redirects to your redirect_uri with ?code=...&state=..., or ?error=access_denied&state=... if the customer declined. The code is valid for 10 minutes and works once.

2. Exchange the code

curl -X POST "https://app.klctai.com/oauth/platform/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code=THE_CODE \
  -d code_verifier=YOUR_VERIFIER \
  -d redirect_uri=https://yourapp.example/klct/callback

You may send client_id and client_secret in the body instead of HTTP Basic.

{
  "access_token": "31|xYz...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "def50200...",
  "scope": "identity contacts:read tickets:read tickets:write"
}

Check scope: it lists what the customer actually allowed, which can be less than you asked for. Then call GET /platform/account to learn which account you are connected to.

3. Refresh

Access tokens last one hour. Refresh tokens last 30 days and rotate on every use: each refresh response contains a new refresh token and the old one stops working. Store the new one every time.

curl -X POST "https://app.klctai.com/oauth/platform/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=refresh_token \
  -d refresh_token=THE_REFRESH_TOKEN

A refresh cannot add scopes. To get more, send the customer through step 1 again with the larger scope.

Revoke

curl -X POST "https://app.klctai.com/oauth/platform/revoke" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d token=THE_ACCESS_OR_REFRESH_TOKEN

Customers can also disconnect your app from Integrations in KLCT. After that every request with that connection's tokens answers 401.

Errors

Token endpoint errors follow RFC 6749: invalid_request, invalid_client (401), invalid_grant (expired or reused code, PKCE mismatch, revoked connection), invalid_scope, unsupported_grant_type. Each comes with an error_description.