OAuth 2.0

Kyo is an OAuth 2.0 provider. Your application sends a user to Kyo's consent screen and receives scoped, revocable tokens to call the REST API on their behalf. The authorization-code flow with PKCE is required for every client — public and confidential alike.

Register an application

Applications are registered inside the Kyo app under Settings → API (workspace admins). Registration is self-serve and gives you a client id (kyoapp_…) plus up to 10 redirect URIs.

  • Public clients — desktop, CLI, and mobile apps that can't keep a secret. No client secret is issued; PKCE alone protects the exchange.
  • Confidential clients — server-side apps. A client secret (kyo_sk_…) is shown once at creation and stored only as a hash — save it immediately.

Apps that haven't been verified by Kyo show a warning banner on the consent screen. Users can still authorize them.

Endpoints

EndpointURL
Authorizationhttps://app.trykyo.com/oauth/authorize
Tokenhttps://pvozbkuhjofzitsmpspf.supabase.co/functions/v1/oauth-token
Revocationhttps://pvozbkuhjofzitsmpspf.supabase.co/functions/v1/oauth-revoke

Token and revocation requests are form-encoded POSTs and also need the public apikey header — the same anon key used for REST API requests.

Authorization flow

Before starting, generate a PKCE pair: a random code_verifier (43–128 characters) and its code_challenge = base64url(SHA-256(verifier)). Only the S256 challenge method is accepted.

1. Send the user to the consent screen

url
https://app.trykyo.com/oauth/authorize
  ?client_id=kyoapp_…
  &redirect_uri=https://yourapp.com/callback
  &response_type=code
  &scope=deals:read%20tasks:write
  &state=…
  &code_challenge=…
  &code_challenge_method=S256

The user signs in to Kyo (if needed), reviews the requested scopes, and approves. Kyo redirects back to your redirect_uri with ?code=kyo_ac_…&state=…. Always verify state matches what you sent.

Authorization codes are single-use and expire after 60 seconds — exchange them immediately.

2. Exchange the code for tokens

bash
curl -X POST "https://pvozbkuhjofzitsmpspf.supabase.co/functions/v1/oauth-token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "apikey: $KYO_ANON_KEY" \
  -d grant_type=authorization_code \
  -d code=kyo_ac_… \
  -d code_verifier=… \
  -d client_id=kyoapp_… \
  -d redirect_uri=https://yourapp.com/callback
response
{
  "access_token": "kyo_at_…",
  "refresh_token": "kyo_rt_…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "deals:read tasks:write"
}

Confidential clients also authenticate this request — either HTTP Basic (client_id:client_secret) or a client_secret body parameter. The PKCE code_verifier is required for all clients. OAuth errors use the standard { "error": "…", "error_description": "…" } shape.

3. Call the API

bash
curl "https://pvozbkuhjofzitsmpspf.supabase.co/functions/v1/api-v1/v1/deals" \
  -H "Authorization: Bearer kyo_at_…" \
  -H "apikey: $KYO_ANON_KEY"

See the REST API reference for everything you can call.

Refreshing tokens

Access tokens live for 1 hour. Use the refresh grant to get a new pair:

bash
curl -X POST "https://pvozbkuhjofzitsmpspf.supabase.co/functions/v1/oauth-token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "apikey: $KYO_ANON_KEY" \
  -d grant_type=refresh_token \
  -d refresh_token=kyo_rt_… \
  -d client_id=kyoapp_…
  • Rotation — every refresh returns a new access + refresh pair and invalidates the old refresh token. Always persist the new one.
  • Reuse detection — replaying an already-rotated refresh token is treated as a compromise: the entire token family is revoked and the user must authorize again.
  • Scope narrowing — pass scope to downgrade; scopes can never be widened on refresh.

Refresh tokens expire after 30 days.

Revoking access

Kyo implements RFC 7009 token revocation:

bash
curl -X POST "https://pvozbkuhjofzitsmpspf.supabase.co/functions/v1/oauth-revoke" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "apikey: $KYO_ANON_KEY" \
  -d token=kyo_rt_… \
  -d token_type_hint=refresh_token \
  -d client_id=kyoapp_…

Revoking a refresh token revokes its whole family. Users can also revoke any authorized app themselves from Settings → API in Kyo.

Scopes

Request scopes as a space-separated list. Scopes are resource:read / resource:write; the wildcard resource:* is also accepted. A token can never exceed what the authorizing user can do in the app.

ScopeGrants
deals:read / deals:writeDeals, plus their person and label links
people:read / people:writeCRM contacts
companies:read / companies:writeCompanies
tasks:read / tasks:writeTasks, including deal tasks
pipelines:read / pipelines:writePipelines and pipeline stages
labels:read / labels:writeLabels
comments:read / comments:writeComments on deals and tasks
spaces:read / spaces:writeSpaces and projects
activity:readThe activity (audit) feed — read only
credits:readWorkspace credit balance — read only
enrich:writeMetered company enrichment

Token reference

TokenPrefixLifetime
Authorization codekyo_ac_60 seconds, single-use
Access tokenkyo_at_1 hour
Refresh tokenkyo_rt_30 days, rotates on every refresh
Client secretkyo_sk_Until deleted; shown once at creation

Kyo tokens are opaque strings, not JWTs — don't try to decode them. They're stored hashed at rest on Kyo's side; treat them like passwords on yours.

Redirect URI rules

  • https is required for web apps, and matching is exact — scheme, host, path, and query.
  • Loopback is allowed for native appshttp://127.0.0.1 and http://localhost URIs may use any ephemeral port: the port is ignored at match time (RFC 8252), so register http://127.0.0.1/callback once.
  • No URL fragments; up to 10 URIs per application.