# Authentication

HMAC-SHA256 based authentication. Every request must include an `Authorization` header.

#### Header Format

```
Authorization: HMAC {api_key}:{signature}:{nonce}:{timestamp}
```

All four parts are separated by `:` with no spaces.

#### Parameters

| Parameter   | Type   | Description                                                                                            |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------ |
| `api_key`   | String | Your API key (provided by Vagon)                                                                       |
| `signature` | String | HMAC-SHA256 **hex digest** of the signing string (see below)                                           |
| `nonce`     | String | A unique random string for each request (e.g., UUID). Must never be reused.                            |
| `timestamp` | String | Current time as **milliseconds since Unix epoch** (e.g., `1712567890123`). Not seconds — milliseconds. |

#### Signature Computation

**Step 1 — Build the signing string**

Concatenate the following values **with no separator** (no spaces, no newlines, no delimiters):

```
{api_key}{HTTP_METHOD}{path}{timestamp}{nonce}{request_body}
```

| Component      | Description                                                                   | Example                                |
| -------------- | ----------------------------------------------------------------------------- | -------------------------------------- |
| `api_key`      | Same API key used in the header                                               | `ak_live_abc123`                       |
| `HTTP_METHOD`  | Uppercase HTTP method                                                         | `POST`, `GET`, `PATCH`, `DELETE`       |
| `path`         | **Full request path** including the base path, without query string or host   | `/organization-management/v1/machines` |
| `timestamp`    | Same timestamp used in the header (milliseconds)                              | `1712567890123`                        |
| `nonce`        | Same nonce used in the header                                                 | `550e8400-e29b-41d4-a716-446655440000` |
| `request_body` | Raw JSON request body. **Empty string for GET/DELETE requests with no body.** | `{"plan_id":1,"quantity":1}`           |

**Step 2 — Sign with HMAC-SHA256**

Sign the concatenated string using your **API secret** as the key, producing a **hex digest** (lowercase).

```
signature = HMAC-SHA256(api_secret, signing_string).hexdigest
```

#### Important Notes

* **Path must be the full path** (e.g., `/organization-management/v1/machines`), without query string or host.
* **Timestamp is in milliseconds**, not seconds (13 digits, e.g., `1712567890123`).
* **GET/DELETE requests** with no body: use an empty string `""` as the `request_body` component.
* **Nonce must be unique** per request (use UUID or random string).
* **Signature is hex-encoded**: lowercase hex string (64 characters for SHA-256), not Base64.

#### Full Example

**Given:**

* API Key: `ak_live_abc123`
* API Secret: `sk_live_xyz789`
* Method: `POST`
* Path: `/organization-management/v1/machines`
* Timestamp: `1712567890123`
* Nonce: `550e8400-e29b-41d4-a716-446655440000`
* Body: `{"plan_id":1,"quantity":1,"region":"dublin"}`

**Step 1 — Signing string (concatenated, no separator):**

```
ak_live_abc123POST/organization-management/v1/machines1712567890123550e8400-e29b-41d4-a716-446655440000{"plan_id":1,"quantity":1,"region":"dublin"}
```

**Step 2 — Compute signature:**

```python
import hmac, hashlib
signing_string = 'ak_live_abc123POST/organization-management/v1/machines1712567890123550e8400-e29b-41d4-a716-446655440000{"plan_id":1,"quantity":1,"region":"dublin"}'
signature = hmac.new(b'sk_live_xyz789', signing_string.encode(), hashlib.sha256).hexdigest()
```

**Step 3 — Final header:**

```
Authorization: HMAC ak_live_abc123:{computed_signature}:550e8400-e29b-41d4-a716-446655440000:1712567890123
```

**GET request example (no body):**

```
signing_string = "ak_live_abc123GET/organization-management/v1/machines1712567890123550e8400-e29b-41d4-a716-446655440000"
```

#### Replay Protection

Requests with a timestamp older than **60 seconds** from the server's current time are rejected. Ensure your system clock is synchronized (NTP recommended).

#### Error Responses

| HTTP Status        | Cause                                                                         |
| ------------------ | ----------------------------------------------------------------------------- |
| `400 Bad Request`  | Missing `Authorization` header                                                |
| `401 Unauthorized` | Invalid signature, expired timestamp, missing token parts, or unknown API key |
