Skip to content

CLI authentication

The KiCI CLI supports three authentication methods: browser-based OAuth (default), device authorization flow (for headless environments), and API key paste (for CI/CD pipelines).

The default kici login flow:

  1. Opens your default browser to the KiCI identity provider
  2. You authenticate in the browser
  3. The CLI receives a token via localhost callback
  4. A personal access token (PAT) is created and stored locally
Terminal window
kici login

The CLI auto-detects headless environments (SSH sessions, CI runners) and switches to device flow automatically.

For environments without a browser (SSH, remote servers):

Terminal window
kici login --device

This displays a URL and a code. Open the URL on any device, enter the code, and authenticate. The CLI polls for completion.

For CI/CD pipelines and automated environments, paste an API key directly:

Terminal window
kici login --token kici_sk_abc123...

The API key (starts with kici_sk_) is passed directly as the flag value and stored in your local config file.

Revoke your PAT and clear local authentication:

Terminal window
kici logout

This:

  1. Revokes the PAT on the server (preventing further use)
  2. Clears auth fields from the local config file
  3. Preserves non-auth settings (active org, default clusters, Platform endpoint)
Terminal window
kici org list

Shows all organizations you belong to, with your role in each. The active organization is marked with an asterisk.

Terminal window
kici org use <name-or-id>

Name matching is case-insensitive. You can also use the organization ID directly.

The active organization is both the scope for org-scoped commands (kici runs list, kici diagnostics, kici secrets list, …) and the default target for kici run remote. After kici login and kici org use <org>, kici run remote dispatches to that org through the Platform — that is the complete path to a remote run. Override the target for a single run with kici run remote --org <id>.

If an organization has more than one connected orchestrator cluster, set its default cluster once with kici orchestrators use <name> (list them with kici orchestrators list). kici run remote then targets that cluster unless you pass --orchestrator <name>. With a single connected orchestrator the cluster is selected automatically.

Terminal window
kici org current

Displays the currently active organization name and ID.

kici org current shows your current login state and active organization:

Terminal window
kici org current

It reports whether you are logged in and which organization is active. PAT expiry and the full list of your tokens are managed from the dashboard (see “Dashboard management” below).

Personal access tokens (PATs) are created automatically when you log in via OAuth. You can also create and manage PATs through the dashboard.

  • User-scoped: PATs work across all organizations you belong to
  • 120-day default expiry: Configurable when creating from the dashboard
  • Named per machine: Each login creates a PAT named after the machine hostname
  • Permission inheritance: PATs inherit your effective role permissions in each org
Personal access tokensAPI keys
ScopeUser (cross-org)Organization
Prefixkici_pat_kici_sk_
Created byCLI login or dashboardDashboard
Expiry120 days (default)No expiry
Use caseDeveloper CLI accessCI/CD pipelines

Create, view, and revoke PATs from the dashboard:

  1. Click your avatar in the sidebar
  2. Select Account settings
  3. Navigate to the Personal access tokens tab

From here you can:

  • Create PATs with custom names and expiry periods
  • View active PATs with their prefixes and expiry dates
  • Revoke PATs that are no longer needed

The Platform exposes a versioned REST API under /api/v1/*. The same endpoints back the dashboard SPA, the kici CLI, and any third-party automation. There is no separate “public” surface — the dashboard’s API is the API.

DeploymentBase URL pattern
KiCI Cloudhttps://<your-platform-host>/api/v1/
Self-hostedhttps://<orchestrator-host>/<deployment-slug>/api/v1/ (slug is optional
KICI_BASE_PATH may add a prefix when the Platform is reverse-proxied)

/api/v1/* requires authentication (see below). /health, /metrics, and /ws (WebSocket) sit outside that prefix and have their own access posture (/metrics is meant for Prometheus scrape, not public exposure).

Every request to /api/v1/* carries an Authorization: Bearer <token> header. The Platform routes on the prefix:

PrefixToken typeCreated viaScope
kici_pat_Personal access tokenkici login or dashboardUser (cross-org)
kici_sk_User API keyDashboard → Settings → API keysOrg
kici_sa_Service account keyDashboard → Settings → Service accountsOrg
(other)OIDC JWT or opaque OIDC tokenOIDC login (browser SPA)User (cross-org)

JWT and opaque OIDC tokens are validated against the configured OIDC issuer (JWKS for JWTs, the issuer’s UserInfo endpoint for opaque ones). All kici_* tokens are validated by SHA-256 hash lookup against the Platform DB. See RBAC: authentication methods for the full model.

Note: kici_ok_ keys are not for the HTTP API — they authenticate orchestrator-to-Platform WebSocket connections only. Use kici_sk_ (or kici_pat_) for HTTP calls.

Tokens authenticate; RBAC authorizes. Every org-scoped route runs orgContextMiddleware (verifies you are a member of the target org) followed by requirePermission(resource, level). The 15 resources and 5 levels are documented in RBAC. User API keys carry their own permission matrix bounded above by the creator’s effective permissions; PATs inherit the user’s role permissions (or are capped further by their scopes field).

The dashboard is a browser SPA on top of the same /api/v1/* surface, so anything you can configure in the dashboard you can configure over HTTP. The mounted route groups include:

  • Auth & identity: /cli/exchange-token, /pats, /user, /identity-links, /github-oauth, /invites, /invites/pending, /invites/:inviteId/{accept,decline}
  • Org & membership: /orgs, /orgs/:customerId, /orgs/:customerId/{members,roles,api-keys,orchestrator-keys,service-accounts,billing,trust-policies}
  • Workflows & runs: /orgs/:customerId/{runs,registrations,workflows,held-runs,environments,secrets,global-workflows}
  • Webhooks & event log: /orgs/:customerId/{sources,webhook-endpoints,event-log}
  • Diagnostics & activity: /orgs/:customerId/{diagnostics,activity,access-log}

The full route tree is the source of truth — every method, request schema, and response schema is enumerated server-side. There is currently no auto-generated OpenAPI spec; the typed DashboardApiType export is the canonical contract for TypeScript clients.

Two short examples — adapt the base URL and token to your deployment.

curl (PAT or API key):

Terminal window
TOKEN="$(grep -E '^pat=' ~/.kici/config | cut -d= -f2)" # or paste a kici_sk_…
ORG="<your-org-id>"
curl -sS \
-H "Authorization: Bearer $TOKEN" \
"https://<orchestrator-host>/<deployment-slug>/api/v1/orgs/$ORG/runs?limit=5" | jq

Browser console (after dashboard login):

const ns = Object.keys(localStorage).find((k) => k.startsWith('oidc.user:'));
const { access_token } = JSON.parse(localStorage.getItem(ns));
const res = await fetch('/<deployment-slug>/api/v1/orgs/<your-org-id>/runs?limit=5', {
headers: { Authorization: `Bearer ${access_token}` },
});
console.log(await res.json());

There is currently no per-token rate limit on /api/v1/*. A single global body-size cap applies to webhook ingress and dashboard API requests alike.

Every /api/v1/* mutation that touches tenant-plane data is recorded in the upstream tenant-plane audit log, stamped with the actor (user, API key, service account, or upstream operator on a break-glass support read). Reads on customer data go through the orchestrator over the WebSocket proxy and land in the orchestrator’s access_log table. See Audit log for the orchestrator schema and the dashboard’s “Activity” page for the federated view.

The CLI stores authentication data in ~/.kici/config with 0600 permissions (owner read/write only). The config file contains:

  • PAT token
  • PAT expiry date
  • Active organization ID
  • Per-org default orchestrator clusters
  • Platform endpoint URL

If kici login can’t open a browser:

  • Use kici login --device for the device flow
  • Or set the KICI_BROWSER_CMD environment variable to your browser command (e.g., KICI_BROWSER_CMD='firefox {url}')

The device flow has a 5-minute timeout. If it expires:

  • Run kici login --device again to get a new code
  • Ensure you’re using the correct URL displayed by the CLI

If you see “Personal access token has expired”:

  • Run kici login to create a new PAT
  • The old expired PAT is automatically superseded

If authenticated commands return 403:

  • Check your active org: kici org current
  • List available orgs: kici org list
  • Switch to the correct org: kici org use <name>

If the CLI can’t reach the server:

  • Verify the endpoint: check ~/.kici/config for the correct URL
  • Test connectivity: curl <your-platform-url>/health