Auth
The CLI authenticates with an organization-scoped API key. Credentials live in an owner-only file at ${XDG_CONFIG_HOME:-~/.config}/khotan/profiles.json (0600, in a 0700 directory), or in environment variables, or in a repo-local .env.khotan.local. Never put an API key in a file committed to the repository.
Store an existing key
Create a key in the dashboard, then:
khotan auth set-key --api-url https://app.example.com --api-key khk_live_...
khotan whoami
Use a per-customer profile name, not default, when one machine talks to more than one organization.
Exchange credentials for a key
khotan login \
--api-url https://app.example.com \
--email you@example.com \
--password '••••••' \
--organization-id org_123
login calls POST /api/v1/api-keys, stores the minted key once, and verifies it. The key itself is never printed to stdout.
Profiles
khotan auth set-key --profile staging --api-url https://staging.example.com --api-key ...
khotan auth use staging
khotan auth list
khotan apps list --profile staging
auth list never prints keys.
Environment variables
Environment variables take precedence over stored profile values, so CI and agent sandboxes need no on-disk state:
| Variable | Purpose |
|---|---|
KHOTAN_API_URL |
API origin |
KHOTAN_API_KEY |
Organization-scoped API key |
KHOTAN_PROFILE |
Select a stored profile by name |
KHOTAN_ORG_ID |
Expected org id; the CLI asserts whoami.organizationId matches it |
export KHOTAN_API_URL=https://app.example.com
export KHOTAN_API_KEY=khk_live_...
khotan apps list --json
Repo-local org isolation
When .env.khotan.local sits at or above the working directory, the CLI auto-loads its KHOTAN_* values so every command is scoped to that repo's organization. Precedence is flag > .env.khotan.local > shell env > profile.
# .env.khotan.local (git-ignored)
KHOTAN_API_URL='https://<workspace>.khotan.com'
KHOTAN_API_KEY='<org-scoped key>'
KHOTAN_ORG_ID='<org id>'
When KHOTAN_ORG_ID or --assert-org <id> is set, every session-bearing command verifies whoami.organizationId before trusting output and fails closed on mismatch (org_mismatch). With no expected org id, behavior is unchanged.
If apps list or context list returns another customer's data, stop. Do not infer deployment or env from CLI output until the org assertion passes. See errors.