I’m trying to authenticate with the Coinbase Advanced API using an ES256-signed JWT, but I keep getting a 401 response from every endpoint.
I’m using a JSON API key created in the Coinbase Developer Platform (CDP), and I’ve confirmed that:
- The key has the correct permissions
- The `kid` in the JWT header matches the API key ID
- The `sub` claim matches the key name (organizations/.../apiKeys/...)
- The token is signed with ES256
- The `aud` is set to `https://api.coinbase.com`
- The `nbf` and `exp` claims are within the correct window
- The HTTP request includes the JWT in the `Authorization: Bearer
I’ve also verified that I’m generating a new JWT for each request, but the response is always:
401 Unauthorized
{"error":"invalid_token"}
Here is a simplified example of how I’m generating the JWT:
Here is a simplified example of how I'm generating the JWT:
```python
import jwt
import json
import time
from pathlib import Path
from cryptography.hazmat.primitives import serialization
# Load JSON API key (Coinbase CDP key)
with open("cdp_api_key.json", "r") as f:
key_data = json.load(f)
# Load EC private key
with open("private_key.pem", "r") as f:
private_key = serialization.load_pem_private_key(
f.read().encode(),
password=None,
)
now = int(time.time())
# JWT payload
payload = {
"sub": key_data["name"],
"iss": key_data["name"],
"nbf": now,
"exp": now + 120,
"aud": "https://api.coinbase.com",
}
# Generate ES256-signed JWT
token = jwt.encode(
payload,
private_key,
algorithm="ES256",
headers={"kid": key_data["id"]},
)
print(token)
Even with this, the request still returns 401.
Even with this, the request still returns 401.
QUESTION:
Is there an additional requirement for Coinbase’s ES256 JWT flow (CDP JSON keys) that isn’t documented, or something subtle that I’m missing?