> ## Documentation index
> Fetch the complete documentation index at: https://docs.katakate.org/llms.txt
> Ask it with GET https://docs.katakate.org/ask?q=<keywords or question>. Short keywords rank best.
> Use these to discover all available pages before exploring further.

# Identity: whoami, keys, role bindings

> Who am I, OIDC discovery, API key minting and OIDC role bindings

These routes manage *who* can call the API. Keys and role bindings need the cluster-wide `admin` role; `whoami` works for every principal; `/auth/oidc` is public. Concepts: [Tenants, roles and OIDC](/k7/guides/tenants-and-roles).

## Who am I

Endpoint: `GET /api/v1/auth/whoami`

<RequestExample>
```bash cURL
curl --cacert ./k7-ca.crt -H "X-API-Key: $K7_API_KEY" "$BASE/api/v1/auth/whoami"
```
</RequestExample>

```json
{
  "data": {
    "type": "key",
    "subject": "k7_a1b2c3",
    "grants": ["user on tenant acme"],
    "issuer": null,
    "groups": null
  }
}
```

`type` is `key` or `oidc`; `subject` is the key id or the OIDC `sub`. `grants` lists the cluster role and/or one `<role> on tenant <name>` per tenant (an unscoped development-mode key shows `user on namespaces …`). For OIDC principals, `issuer` and `groups` echo the token so you can debug claim shapes.

## OIDC discovery

Endpoint: `GET /api/v1/auth/oidc` (no authentication)

What `k7 login` needs to start a device or PKCE flow: `issuer`, `client_id`, `audience`. `404` when the cluster was installed without the `--oidc-*` flags.

## API keys

Keys are stored as `sha256(secret)` in the `kube-system/k7-api-keys` Secret; every replica sees a change within 5 s. These routes are the `--api` path of `k7 generate-api-key` / `list-api-keys` / `revoke-api-key`.

### Mint a key

Endpoint: `POST /api/v1/keys` — `admin`

<RequestExample>
```bash cURL
curl --cacert ./k7-ca.crt -X POST "$BASE/api/v1/keys" \
  -H "X-API-Key: $K7_ADMIN_KEY" -H "Content-Type: application/json" \
  -d '{"name": "acme-ci", "role": "user", "tenant": "acme", "expires_days": 90, "namespaces": ["acme-dev"], "nodes": []}'
```
</RequestExample>

<ResponseExample>
```json 201 Created
{
  "data": {
    "id": "k7_9f8e7d",
    "name": "acme-ci",
    "role": "user",
    "tenant": "acme",
    "namespaces": ["acme-dev"],
    "nodes": [],
    "created": 1760745600,
    "expires": 1768521600,
    "last_used": null,
    "token": "k7_9f8e7d_<secret>"
  }
}
```
</ResponseExample>

<ParamField body="name" type="string" required>Human label; several keys may share it (revoke acts on all of them)</ParamField>
<ParamField body="role" type="string" required>`read-only` | `user` (per tenant) | `operator` | `admin` (cluster-wide)</ParamField>
<ParamField body="tenant" type="string">Required for `read-only`/`user` in production mode; forbidden for `operator`/`admin`. Must exist</ParamField>
<ParamField body="expires_days" type="integer" required>Positive integer</ParamField>
<ParamField body="namespaces" type="string[]">Narrow the key inside its tenant</ParamField>
<ParamField body="nodes" type="string[]">Kubernetes node names the key may place sandboxes on (`k7 nodes list`)</ParamField>

The `token` is returned **once**. A role/tenant mismatch or an unknown tenant is `400`.

### List and revoke

- `GET /api/v1/keys` — `admin`. Every key without its hash, plus `last_used`.
- `DELETE /api/v1/keys/{name}` — `admin`. Revokes every key with that name; `404` if none. Returns `{"revoked": [ids]}`.

## Role bindings

Map OIDC groups, usernames or subjects to roles. Stored in ConfigMap `k7-role-bindings`, read on every request.

Endpoints: `GET /api/v1/role-bindings`, `PUT /api/v1/role-bindings` — `admin`

<RequestExample>
```bash cURL
curl --cacert ./k7-ca.crt -X PUT "$BASE/api/v1/role-bindings" \
  -H "Authorization: Bearer $K7_ADMIN_KEY" -H "Content-Type: application/json" \
  -d '{
    "bindings": [
      {"group": "platform-admins", "role": "admin"},
      {"group": "sre", "role": "operator"},
      {"group": "acme-devs", "role": "user", "tenant": "acme"},
      {"user": "auditor@example.com", "role": "read-only", "tenant": "acme"}
    ],
    "deny_subjects": ["former-employee@example.com"]
  }'
```
</RequestExample>

Each binding has exactly one matcher (`group`, `user` or `subject`) plus `role` and, for tenant roles, `tenant`. Several matching bindings combine as the highest role per tenant plus the highest cluster role. `deny_subjects` (OIDC `sub` or username) is the immediate stop for an account: it applies on the next request on every replica, whereas a JWT otherwise stays valid until it expires.

`PUT` replaces the whole document and is `400` on an unknown tenant, a role/tenant mismatch, a duplicate matcher, or a write that would leave no `admin` binding while no unexpired `admin` key exists (lock-out guard). CLI: `k7 role-bindings get` / `apply -f`.
