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

# API Authentication

This guide shows how to obtain a JWT and use it for authenticated REST and WebSocket access.

***

## 1) Obtain a JWT

Request a token from the authorization endpoint:

```http theme={null}
POST /api/v1/authorize
Content-Type: application/json
```

Example body:

```json theme={null}
{
  "public_key": "<Canton Party ID>",
  "signature": "",
  "timestamp_ms": 1731541800000,
  "nonce": "random-unique-string"
}
```

* `public_key`: Canton Party ID associated with the user
* `timestamp_ms`: Unix time in milliseconds
* `nonce`: Unique value generated for the authorization request

Successful response:

```json theme={null}
{ "token": "<jwt>", "user_id": "<user_id>" }
```

Token validity: 7 days from issuance.

***

## 2) API Key Auth

Gateway supports API-key auth headers for programmatic access without obtaining a JWT first.

Headers:

* `X-API-KEY`: Your API public key
* `X-SIGNATURE`: Ed25519 signature over `EKIDEN_API|{method}|{uri}|{timestamp_ms}|{nonce}`
* `X-TIMESTAMP-MS`: Unix milliseconds
* `X-NONCE`: Random unique string

***

## 3) Use the token for REST

Include the token as a Bearer in the Authorization header:

```http theme={null}
GET /api/v1/user/portfolio
Authorization: Bearer <jwt>
```

Private endpoints under `/api/v1/user/*` and certain actions require this header.

***

## 4) Use the token for private WebSocket

Connect to the private WS endpoint and authenticate, then subscribe to private topics:

1. Connect: `wss://api.cnt.ekiden.fi/ws/private`
2. Authenticate:

Client → Server

```json theme={null}
{ "op": "auth", "bearer": "<jwt>", "req_id": "auth-1" }
```

Server → Client

```json theme={null}
{ "op": "auth", "success": true, "user_id": "<user_id>", "req_id": "auth-1" }
```

3. Subscribe to private topics (examples):

```json theme={null}
{ "op": "subscribe", "args": ["order", "position", "execution", "account_balance"], "req_id": "sub-1" }
```

Public topics like `orderbook.1.BTCUSDC`, `trade.BTCUSDC`, `ticker.BTCUSDC` are available on `/ws/public` without auth.

***

## Timestamp units and replay protection

* `timestamp_ms` is required in the authorize request and must be close to server time.
* Each `(public_key, nonce)` pair may be used once; reusing a nonce will be rejected.

***

## Optional: curl examples

Request token:

```bash theme={null}
curl -X POST "https://api.cnt.ekiden.fi/api/v1/authorize" \
    -H "Content-Type: application/json" \
    -d '{
        "public_key": "<Canton Party ID>",
        "signature": "",
        "timestamp_ms": 1731541800000,
        "nonce": "b7d1c2e8f5a94f3db2f8c6a9d1e4"
    }'
```

Call a private REST endpoint:

```bash theme={null}
curl -H "Authorization: Bearer <jwt>" \
    "https://api.cnt.ekiden.fi/api/v1/user/portfolio"
```

***

## Troubleshooting

* 400 on /authorize: check the request payload, timestamp\_ms freshness, and nonce validity.
* 401 on private REST or WS auth: token expired or invalid.
* WS: authenticate before subscribing to private topics on `/ws/private`.
