# Authentication

## 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"**
   - Select **Trader** for trading methods such as `order.place`; **Auditor** or **Trader** is sufficient for `positions@account`
5. Save your API key and secret securely

:::warning
Only **account-scoped** keys with **time-based** nonces are accepted. Account keys use the `account-...` prefix. Master or group keys, such as `master-...` keys, are rejected with HTTP 401.
:::

---

## Create an Authenticated Connection

Connect to `wss://ws.gemini.com` and pass the following headers when establishing the WebSocket connection:

| Header | Value |
|--------|-------|
| `X-GEMINI-APIKEY` | Your account-scoped Gemini API key |
| `X-GEMINI-NONCE` | Decimal nonce |
| `X-GEMINI-PAYLOAD` | `base64(string(nonce))` |
| `X-GEMINI-SIGNATURE` | `hex(hmac_sha384(payload, api_secret))` |

:::note
Auditor or Trader role is sufficient for `positions@account`. Trader role is required for trading operations such as `order.place`.
:::

:::note
Before sending trading orders, check `GET /v1/prediction-markets/terms/status`. If `hasAcceptedLatest` is `false`, display `GET /v1/prediction-markets/terms` and accept with `POST /v1/prediction-markets/terms/accept`, then retry the order.
:::

:::warning
Authentication headers must be provided during the initial WebSocket handshake. You cannot authenticate after the connection is established.
:::

### Signature Generation Step-by-Step

```text
# Create a monotonically increasing integer nonce.
# Unix seconds or Unix milliseconds are both accepted, but the value must
# increase across connections for the same key.
nonce = current_unix_timestamp_in_seconds_or_milliseconds

# Base64 encode the string form of the nonce.
payload = base64_encode(string(nonce))

# 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 `positions@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).
:::
