You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We see intermittent 401 Unauthorized for correctly-signed CDP JWTs on the Advanced Trade REST API same key, same endpoint, same machine, with a token that validates locally and is accepted on the next attempt. Roughly 40–55% of requests fail when issued from R (via libcurl/httr2), whereas the official Python SDK is ~100% reliable and the curl CLI ~98%.
I am building an R wrapper for the API. R is a mainstream language for quantitative finance, so I would love this to work reliably and I am posting as an open question, since we cannot tell from the client side where the rejection originates.
Environment
GET https://api.coinbase.com/api/v3/brokerage/transaction_summary (also seen on /accounts, /key_permissions)
macOS (Apple Silicon), residential US IP; key created hours earlier, can_view/can_trade true
JWT: ES256, iss: "cdp", sub/kid = full key name, nbf = now, exp = now + 120, uri = "GET api.coinbase.com/api/v3/brokerage/transaction_summary", random nonce
Observed (same key, same machine, same minute)
Client
TLS stack
Success
coinbase-advanced-py (urllib3)
OpenSSL
~100% (20/20, repeated)
curl CLI (libcurl)
LibreSSL
~98%
R httr2 → libcurl 8.20.0
OpenSSL 3.6.2
~55%
The 401 body is a bare Unauthorized, served via Cloudflare (cf-ray) but carrying a Coinbase trace-id, so it reaches the origin. A byte-identical token that returns 401 returns 200 on retry.
The same loop via the curl CLI (fresh JWT per call) is far more reliable, though it still 401s occasionally.
Already ruled out
Token validity (self-verifies; works via curl); request rate/spacing (3–5 s jittered spacing, controlled A/B no difference); JWT claims and uri formatting; nonce, User-Agent, Accept-Encoding; HTTP/1.1 vs HTTP/2; connection reuse vs fresh connections; persistent session vs fresh process per request; TLS 1.2 vs 1.3; libcurl version (8.7.1 vs 8.20.0); TLS backend (SecureTransport vs OpenSSL).
The only consistent predictor of reliability is which HTTP client / TLS stack issues the request.
Questions
Does the edge/auth layer apply any client- or TLS-fingerprint-based filtering that might reject valid JWTs from some libcurl clients?
Summary
We see intermittent
401 Unauthorizedfor correctly-signed CDP JWTs on the Advanced Trade REST API same key, same endpoint, same machine, with a token that validates locally and is accepted on the next attempt. Roughly 40–55% of requests fail when issued from R (via libcurl/httr2), whereas the official Python SDK is ~100% reliable and thecurlCLI ~98%.I am building an R wrapper for the API. R is a mainstream language for quantitative finance, so I would love this to work reliably and I am posting as an open question, since we cannot tell from the client side where the rejection originates.
Environment
GET https://api.coinbase.com/api/v3/brokerage/transaction_summary(also seen on/accounts,/key_permissions)can_view/can_tradetrueiss: "cdp",sub/kid= full key name,nbf = now,exp = now + 120,uri = "GET api.coinbase.com/api/v3/brokerage/transaction_summary", randomnonceObserved (same key, same machine, same minute)
coinbase-advanced-py(urllib3)curlCLI (libcurl)httr2→ libcurl 8.20.0The
401body is a bareUnauthorized, served via Cloudflare (cf-ray) but carrying a Coinbasetrace-id, so it reaches the origin. A byte-identical token that returns401returns200on retry.Minimal reproduction (R)
The same loop via the
curlCLI (fresh JWT per call) is far more reliable, though it still 401s occasionally.Already ruled out
Token validity (self-verifies; works via
curl); request rate/spacing (3–5 s jittered spacing, controlled A/B no difference); JWT claims anduriformatting; nonce, User-Agent,Accept-Encoding; HTTP/1.1 vs HTTP/2; connection reuse vs fresh connections; persistent session vs fresh process per request; TLS 1.2 vs 1.3; libcurl version (8.7.1 vs 8.20.0); TLS backend (SecureTransport vs OpenSSL).The only consistent predictor of reliability is which HTTP client / TLS stack issues the request.
Questions
401instead of429(cf. get_candles throttling returns "401 Unauthorized" instead of "Too Many Requests" #60)? Our spacing test suggests not.Happy to provide packet captures or JA3/JA4 fingerprints. Thank you!