> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Client Credentials

> List, add, update, and delete authentication credentials attached to a client

Each client can have one or more **credentials** — the actual authentication materials KnoxCall checks when a request arrives. Two credential kinds are available in v1:

| Kind              | Description                                                                                                                                                                      |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ip`              | An IP address or CIDR range. Matched against the incoming source IP.                                                                                                             |
| `mtls_thumbprint` | A client certificate SHA-256 thumbprint for mTLS authentication. KnoxCall can issue the certificate for you (`mode: "issue"`) or you can register an existing cert's thumbprint. |

***

## List Credentials

```text theme={"dark"}
GET /v1/clients/:id/credentials
```

Returns all credentials attached to a client.

### Path Parameters

| Parameter | Type | Description   |
| --------- | ---- | ------------- |
| `id`      | uuid | The client ID |

### Response

```json theme={"dark"}
{
  "data": [
    {
      "id": "cred-uuid-1",
      "client_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "tenant_id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
      "kind": "ip",
      "label": "Primary office",
      "data": { "value": "203.0.113.0/24", "notes": "" },
      "enabled": true,
      "expires_at": null,
      "created_at": "2026-01-15T09:30:00.000Z",
      "updated_at": "2026-01-15T09:30:00.000Z",
      "last_matched_at": "2026-05-20T14:22:01.000Z"
    }
  ],
  "meta": { "request_id": "550e8400-e29b-41d4-a716-446655440000" }
}
```

### Errors

| Status | Type        | Description      |
| ------ | ----------- | ---------------- |
| 404    | `not_found` | Client not found |

***

## Add Credential

```text theme={"dark"}
POST /v1/clients/:id/credentials
```

Attaches a new credential to a client.

### Path Parameters

| Parameter | Type | Description   |
| --------- | ---- | ------------- |
| `id`      | uuid | The client ID |

### Request Body

| Field   | Type   | Required | Description                                |
| ------- | ------ | -------- | ------------------------------------------ |
| `kind`  | string | Yes      | Credential type: `ip` or `mtls_thumbprint` |
| `label` | string | No       | Human-readable label                       |
| `data`  | object | Yes      | Kind-specific data (see below)             |

**For `kind: "ip"`:**

```json theme={"dark"}
{ "value": "203.0.113.42" }
```

`value` must be a valid IPv4/IPv6 address or CIDR range. The stored `data` object also carries a `notes` string (empty unless set via the client's `ip_address` dual-write path), so credential responses for `kind: "ip"` return `data` as `{ "value": ..., "notes": ... }`.

**For `kind: "mtls_thumbprint"` — issue a new certificate:**

```json theme={"dark"}
{ "mode": "issue" }
```

KnoxCall mints a certificate from your tenant CA, stores only the thumbprint, and returns the PEM bundle once in the `reveal` field. The private key is never stored.

**For `kind: "mtls_thumbprint"` — register an existing certificate:**

```json theme={"dark"}
{ "sha256_thumbprint": "a1b2c3...64-hex-chars" }
```

`sha256_thumbprint` must be a SHA-256 hex digest. Non-hex characters are stripped before validation, and the remaining string must be exactly 64 hex characters or the request fails with `400 validation_error` (`data.sha256_thumbprint must be a SHA-256 hex digest (64 hex chars).`).

### Response

```json theme={"dark"}
{
  "data": {
    "id": "cred-uuid-1",
    "client_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "tenant_id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "kind": "ip",
    "label": "Primary office",
    "data": { "value": "203.0.113.0/24", "notes": "" },
    "enabled": true,
    "expires_at": null,
    "created_at": "2026-01-15T09:30:00.000Z",
    "updated_at": "2026-01-15T09:30:00.000Z",
    "last_matched_at": null
  },
  "meta": { "request_id": "550e8400-e29b-41d4-a716-446655440000" }
}
```

For `mtls_thumbprint` with `mode: "issue"`, the response also includes a one-time `reveal` field:

```json theme={"dark"}
{
  "data": {
    "id": "cred-uuid-2",
    "client_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "tenant_id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "kind": "mtls_thumbprint",
    "data": { "sha256_thumbprint": "a1b2...", "subject": "CN=...", "serial": "...", "not_after": "2027-01-15T09:30:00Z" },
    "enabled": true,
    "expires_at": "2027-01-15T09:30:00Z",
    "reveal": {
      "certificate_pem": "-----BEGIN CERTIFICATE-----\n...",
      "private_key_pem": "-----BEGIN PRIVATE KEY-----\n...",
      "ca_chain_pem": "-----BEGIN CERTIFICATE-----\n..."
    }
  },
  "meta": { "request_id": "550e8400-e29b-41d4-a716-446655440000" }
}
```

<Warning>
  The `reveal.private_key_pem` is returned only once. Store it immediately — it is not retrievable again.
</Warning>

### Errors

| Status | Type               | Description                                               |
| ------ | ------------------ | --------------------------------------------------------- |
| 400    | `validation_error` | Missing or invalid `kind`, or invalid `data` for the kind |
| 404    | `not_found`        | Client not found                                          |

***

## Update Credential

```text theme={"dark"}
PATCH /v1/clients/:id/credentials/:credId
```

Enables/disables a credential or updates its label.

### Path Parameters

| Parameter | Type | Description       |
| --------- | ---- | ----------------- |
| `id`      | uuid | The client ID     |
| `credId`  | uuid | The credential ID |

### Request Body

At least one field is required.

| Field     | Type    | Description                       |
| --------- | ------- | --------------------------------- |
| `enabled` | boolean | Enable or disable this credential |
| `label`   | string  | Update the credential label       |

### Response

Returns the updated credential object.

### Errors

| Status | Type               | Description                            |
| ------ | ------------------ | -------------------------------------- |
| 400    | `validation_error` | Neither `enabled` nor `label` provided |
| 404    | `not_found`        | Credential not found                   |

***

## Delete Credential

```text theme={"dark"}
DELETE /v1/clients/:id/credentials/:credId
```

Removes a credential from a client. For mTLS thumbprint credentials, the underlying certificate is also revoked in the tenant CA's CRL.

### Path Parameters

| Parameter | Type | Description       |
| --------- | ---- | ----------------- |
| `id`      | uuid | The client ID     |
| `credId`  | uuid | The credential ID |

### Response

```json theme={"dark"}
{
  "data": { "deleted": true },
  "meta": { "request_id": "550e8400-e29b-41d4-a716-446655440000" }
}
```

### Errors

| Status | Type        | Description          |
| ------ | ----------- | -------------------- |
| 404    | `not_found` | Credential not found |
