# Authentication Two concepts only — an API key (account-wide or project-scoped) for anything programmatic, or a Supabase JWT for web apps. Canonical page: https://kortix.com/docs/sdk/auth Kortix has exactly two ways to authenticate: a **session** (you logged in) and an **API key** (everything programmatic — the SDK, the CLI, your backend, CI). The SDK takes one via `getToken`, which it sends as `Authorization: Bearer `. ## API key — the one programmatic credential Create one in **User settings → API keys → Create API key**. Name it, choose its scope, copy it once (shown only at creation), and store it as a secret. An API key **acts as you**, so it can reach every project your account can. > **Warn** > Don't use a **Service account** here. Service accounts (`kortix_sa_…`) are a separate, advanced > IAM principal with **no project access until it's explicitly granted** — point the SDK at one and > every call returns `403 "You do not have access to this project"`. For the SDK, the CLI, and the > white-label demo, you want an **API key** from **Settings → API keys**. ```ts const kortix = createKortix({ backendUrl: 'https://api.kortix.com/v1', getToken: async () => process.env.KORTIX_API_KEY!, }); ``` ### Scope — account-wide or one project Scope is a property of the key, picked at creation: | scope | the key can touch | use it for | | --------------------- | ------------------------------------------- | ----------------------------------------- | | **Account** (default) | every project in your account | a backend managing your workspace | | **Project** | exactly one project — `403` everywhere else | CI/CD bound to one repo (least privilege) | Pick the narrowest scope that does the job. Rotate by creating a new key and revoking the old one. > **Note** > The **CLI** mints an API key for you — `kortix login` runs the browser authorize flow and stores > the key locally. Same credential, nothing special — there's no separate "CLI token." ## Supabase JWT — web apps on Kortix login Only if you're building a web app on Kortix's own auth. Return the user's live session token; it refreshes itself, so `getToken` re-reads it each call: ```ts getToken: async () => (await supabase.auth.getSession()).data.session?.access_token ?? null, ``` ## Which one? | you're building | use | | ------------------------- | ------------------------------------------------------- | | a backend, script, or CI | an **API key** (account-wide, or project-scoped for CI) | | the Kortix CLI | `kortix login` (mints an API key for you) | | a web app on Kortix login | a **Supabase JWT** | > **Note** > API keys are bearer credentials — treat them like passwords. Keep them in a secret manager, never > in client-side code or a committed file. `getToken` is called on demand, so the host owns storage, > caching, and rotation.