# Authentication

Every WebSocket connection must be authenticated with a valid API key.

## API key format

```
dsk_<64 hex characters>
```

Example:

```
dsk_a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890ab
```

* Prefix: `dsk_` (always)
* Body: 64 hexadecimal characters (32 random bytes)

## Passing your API key

### Method 1: HTTP header (recommended)

Set the `X-API-Key` header during the WebSocket handshake:

```
X-API-Key: dsk_your_key_here
```

{% hint style="success" %}
This is the recommended method. The key stays out of URLs and server logs.
{% endhint %}

### Method 2: Query parameter

Append the key as a query parameter:

```
wss://cryptolisting.ws?api_key=dsk_your_key_here
```

{% hint style="danger" %}
**Not recommended.** Query parameters may appear in server access logs, proxy logs, and browser history. Use the header method whenever possible.
{% endhint %}

## Key properties

Each API key has the following properties, configured by the administrator:

| Property            | Description                                                      |
| ------------------- | ---------------------------------------------------------------- |
| **Tier**            | Subscription tier: `basic`, `premium`, or `enterprise`           |
| **Max connections** | Maximum simultaneous WebSocket connections allowed with this key |
| **Allowed CEX**     | Exchanges this key can subscribe to (`"*"` = all)                |
| **Expiration**      | Optional expiration date -- key becomes invalid after this time  |

## Key lifecycle

1. **Created** -- The administrator generates a key. The full key is shown exactly once.
2. **Active** -- The key can be used to connect. Connections are subject to the key's limits.
3. **Expired** -- If the key has an expiration date and that date has passed, connections are refused and active sessions are disconnected with close code `1000` and reason `key_expired`.
4. **Revoked** -- The administrator revokes the key. All active sessions are immediately disconnected with close code `1000` and reason `key_revoked`. The key can no longer be used.

## Security

* Keys are **hashed with SHA-256** before storage. Even if the database is compromised, your raw key cannot be recovered.
* Keys are transmitted over **TLS-encrypted** WebSocket connections (WSS).
* Invalid keys are cached server-side for 30 seconds to prevent brute-force attempts.
