# Login auth

URL: https://docs.hanzo.ai/docs/openapi/kms/post-kms-auth-login

> Exchanges a machine credential for an IAM bearer token.

`POST /v1/kms/auth/login`

> [KMS →](https://docs.hanzo.ai/docs/openapi/kms) · [All API references →](https://docs.hanzo.ai/docs/openapi) · [Get started →](https://docs.hanzo.ai/docs/guides)

|               |                                          |
| ------------- | ---------------------------------------- |
| **Address**   | `https://api.hanzo.ai/v1/kms/auth/login` |
| **Method**    | `POST`                                   |
| **Operation** | `post_kms_auth_login`                    |
| **Auth**      | `Authorization: Bearer $HANZO_API_KEY`   |

Exchanges a machine credential for an IAM bearer token.

Takes a tenant's machine credential — a client id and client secret — and
returns an owner-scoped IAM access token with its lifetime, which is the
bearer the caller then carries on the org-scoped secret operations.

It is deliberately public and unauthenticated, because it IS the credential
exchange and runs before any principal exists. That makes it the one route in
this subsystem rate-limited PER SOURCE IP, keyed on the real TCP peer rather
than on any caller-supplied header, and body-capped in the same place.

The submitted secret is never logged and never echoed, and failures collapse
to one clean status with no upstream detail: 401 when the credential does not
authenticate, 502 when the identity provider is unreachable, 503 when no
issuer is configured. That is on purpose — a richer error would be a validity
oracle for guessed credentials.

## Request

2 fields, body `application/json` (required).

| Field          | In   | Type   | Required | Description                                              |
| -------------- | ---- | ------ | -------- | -------------------------------------------------------- |
| `clientId`     | body | string | —        | ClientID is the machine identity's id, as IAM issued it. |
| `clientSecret` | body | string | —        | ClientSecret is that identity's secret.                  |

## Response

| Status    | Body            | Meaning |
| --------- | --------------- | ------- |
| `200`     | kms.kmsToken    | ok      |
| `default` | problem-details | refused |

`200` body — 3 fields.

| Field         | In   | Type            | Always | Description                                                       |
| ------------- | ---- | --------------- | ------ | ----------------------------------------------------------------- |
| `accessToken` | body | string          | —      | AccessToken is IAM's own JWT, verbatim.                           |
| `expiresIn`   | body | integer (int64) | —      | ExpiresIn is the token's lifetime in seconds, as IAM reported it. |
| `tokenType`   | body | string          | —      | TokenType is `Bearer`.                                            |

Failure carries the platform error shape — see [Errors](https://docs.hanzo.ai/docs/errors).

## Examples

**CLI**

```bash
hanzo kms auth login
```

**SDK**

**.ts**

```ts
import { Configuration, KmsApi } from 'hanzoai';

const api = new KmsApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postKmsAuthLogin({ clientId: "<clientId>", clientSecret: "<clientSecret>" });
```

**.py**

```python
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import KmsApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = KmsApi(client).post_kms_auth_login(client_id="<clientId>", client_secret="<clientSecret>")
```

**.go**

```go
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.KmsAPI.PostKmsAuthLogin(context.Background()).Execute()
if err != nil {
	return err
}
```

**.rs**

```rust
use hanzo_client::apis::{configuration::Configuration, kms_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = kms_api::post_kms_auth_login(&cfg, Default::default()).await?;
```

**.java**

```java
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.KmsApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new KmsApi(client).postKmsAuthLogin();
```

**HTTP**

```bash
curl -X POST https://api.hanzo.ai/v1/kms/auth/login \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "clientId": "<clientId>",
       "clientSecret": "<clientSecret>"
     }'
```

**MCP**

MCP reaches **kms** through the `kms` tool, which names its 2 operations with its own verbs — this one among them, under a name only MCP declares. `describe` explains any of them:

```bash
curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "describe",
         "arguments": {
           "op": "get_kms_config"
         }
       }
     }'
```

---

[KMS API](https://docs.hanzo.ai/docs/openapi/kms) · [All Hanzo APIs](https://docs.hanzo.ai/docs/openapi) · [Interactive reference](https://docs.hanzo.ai/docs/openapi/reference)
