# Authentication

The WebSocket API accepts either an HMAC-signed API key or an OAuth 2.0 bearer token on the connection upgrade. Pick whichever fits your app.

## Generate an API Key

API keys for our WebSocket API have special requirements:

1. Navigate to [API Settings](https://exchange.gemini.com/settings/api)
2. Click **"Create API key"**
3. **Scope:** Select the account you want to trade with
4. **Settings:**
   - ✅ Enable **"Uses a time-based nonce"**
   - ✅ Enable **"Trading"**
5. Save your API key and secret securely

:::warning
Only **account-scoped** keys with **time-based** nonces are accepted.
:::

---

## Create an Authenticated Connection

Pass the following headers when establishing the websocket connection,
| Header             | Value                                                   |
|--------------------|---------------------------------------------------------|
| `X-GEMINI-APIKEY`    | Your Gemini API key (session key)                     |
| `X-GEMINI-NONCE`     | Current epoch timestamp in seconds |
| `X-GEMINI-SIGNATURE` | `hex(HMAC_SHA384(base64(nonce), key=api_secret))` |
| `X-GEMINI-PAYLOAD`   | `base64(nonce)`                         |


:::note
Authentication is required for trading operations and order event subscriptions. Market data streams are available without authentication.
:::
:::warning
Authentication headers must be provided during the initial WebSocket handshake—you cannot authenticate after the connection is established.
:::

### Signature Generation Step-by-Step

```pseudo
# Create a nonce from the current epoch time in seconds
nonce = current_timestamp_in_seconds

# Our payload will be the base64 encoded nonce for simplicity
payload = base64_encode(nonce.toString)

# Generate a signature using the hmac_sha384 algorithm
signature = hmac_sha384(payload, api_secret)

# Convert the signature to hex so it can be passed in the headers
hexSignature = hex(signature)
```

---

## Alternative: OAuth 2.0 Bearer Token

If your application uses [OAuth 2.0](/authentication/oauth) to access the Gemini API, you can authenticate the WebSocket connection with the same access token instead of provisioning an API key.

Pass the access token in the `Authorization` header on the WebSocket upgrade request:

| Header          | Value                    |
|-----------------|--------------------------|
| `Authorization` | `Bearer <access_token>`  |

When using OAuth, you do **not** send the `X-GEMINI-APIKEY`, `X-GEMINI-NONCE`, `X-GEMINI-PAYLOAD`, or `X-GEMINI-SIGNATURE` headers.

:::note
The access token must have scopes that cover the streams you intend to subscribe to (for example, `orders:read` for `orders@account`). See [OAuth scopes](/authentication/oauth#oauth-scopes).
:::

:::warning
Access tokens are short-lived (default 24 hours). If the token expires during a session, the server will close the connection and you must reconnect with a refreshed token — tokens cannot be rotated on a live connection. See [Using Refresh Tokens](/authentication/oauth#using-refresh-tokens).
:::
