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

# Coinbase Derivatives: Predictions WebSocket Authentication

Every connection must authenticate before the gateway routes any command. Include the credential keys in your first command, which must be `subscribe`, `unsubscribe`, or `list_subscriptions`. Any other first command fails authentication. You do not need to send credentials on later commands.

Authentication lasts for the life of the connection. If the connection drops, reconnect, authenticate again, and resubscribe.

## Authentication

> [!TIP]
>
> Keys are required (`Y`), optional (`N`), or conditionally required (`C`). Conditional keys are required based on the presence or value of other keys.

| Key | Type | Req | Description |
| :- | :- | :- | :- |
| `key` | String | C | Your API key. Required on the first command. |
| `passphrase` | String | C | Your API passphrase. Must not be empty. Required on the first command. |
| `signature` | String | C | Exactly 44 characters of standard padded Base64 that decodes to 32 bytes. Required on the first command. See [Signature](#signature). |
| `time` | String | C | Current Unix epoch time in seconds, as a base-10 integer string with no decimal point, whitespace, leading `+`, or leading zeros. Required on the first command. |

Example authenticated first command, using the test values from [Signature example](#signature-example):

```json theme={null}
{
  "id": 1,
  "cmd": "subscribe",
  "key": "fixed-api-key",
  "passphrase": "fixed-passphrase",
  "signature": "xGbr3oY2MKYu/HoFjzTX1i2jhltEx/jGFd//lF+49pw=",
  "time": "1717171717",
  "params": {
    "channels": ["ticker"],
    "ticker": "NFL-GAMEWINNER-26NOV28LARSF-LAR"
  }
}
```

The credential keys sit at the top level of the command object, next to `id`, `cmd`, and `params`. See [Command keys](/derivatives-predictions/websocket/commands.md#command-keys).

## Signature

1. Concatenate these strings without delimiters: `time + key + "CPM_WEB_MARKETDATA" + passphrase`. Use the exact `time`, `key`, and `passphrase` values you send.
2. Do not trim or Unicode-normalize the API key or passphrase.
3. Encode the concatenated text once as UTF-8.
4. Decode your signing secret with standard Base64.
5. Compute HMAC-SHA256 over the UTF-8 bytes, keyed with the decoded secret.
6. Encode the 32-byte result with standard padded Base64 and send it as `signature`.

The command's `id`, `cmd`, and `params` are not signed. The signature authenticates the whole connection.

> [!NOTE]
>
> `time` must be within 30 seconds of the server's clock, inclusive, in either direction: `server_time - 30` to `server_time + 30`.

### Signature example

These are test values only. The signing secret `a2V5` is the Base64 encoding of the text `key`. Use it only to check your signing code, and never share your real secret.

| Input or step | Value |
| :- | :- |
| `time` | `1717171717` |
| `key` | `fixed-api-key` |
| `passphrase` | `fixed-passphrase` |
| Signing secret | `a2V5` (Base64) |
| Prehash string | `1717171717fixed-api-keyCPM_WEB_MARKETDATAfixed-passphrase` |
| HMAC-SHA256 (hex) | `c466ebde863630a62efc7a058f34d7d62da3865b44c7f8c615dfff945fb8f69c` |
| `signature` | `xGbr3oY2MKYu/HoFjzTX1i2jhltEx/jGFd//lF+49pw=` |

Example in Python:

```python theme={null}
import base64, hashlib, hmac

time, key, passphrase = "1717171717", "fixed-api-key", "fixed-passphrase"
secret = base64.b64decode("a2V5")
prehash = (time + key + "CPM_WEB_MARKETDATA" + passphrase).encode("utf-8")
signature = base64.b64encode(hmac.new(secret, prehash, hashlib.sha256).digest()).decode()
# signature == "xGbr3oY2MKYu/HoFjzTX1i2jhltEx/jGFd//lF+49pw="
```

## Authorization

Authentication succeeds when all of the following are true:

* The signature is valid for the API key and passphrase.
* The API key exists.
* The API key's user is active and has the `MARKET_DATA` permission.
* The user's Firm or FCM is active.

If authentication fails, the server sends an error with code `7` and text `Unable to authenticate`, then closes the WebSocket with close code `3000` and reason `Unauthorized User`. Open a new connection with a fresh `time` and `signature` to retry. See [Errors](/derivatives-predictions/websocket/overview.md#errors).

Example authentication failure:

```json theme={null}
{
  "id": 1,
  "type": "error",
  "msg": {
    "code": 7,
    "msg": "Unable to authenticate"
  }
}
```

> [!NOTE]
>
> A newly created or rotated API key may take up to 5 seconds to become usable.

## Commands sent while authentication is pending

You can send more commands before authentication completes. The server queues them and runs them in order after authentication succeeds. See [Limits](/derivatives-predictions/websocket/overview.md#limits) for the queue size and the authentication timeout.
