> For the complete documentation index, see [llms.txt](https://docs.khotan.com/llms.txt). A markdown version of any page is available at its `index.md` URL.

# 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:

```sh
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

```sh
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

```sh
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 |

```sh
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`.

```txt
# .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](/cli/errors/).
