使用CDP JWT认证调用Coinbase V2交易接口分页时返回401错误的技术求助
Let's break down the issues you're facing and walk through actionable troubleshooting steps:
1. Most Likely Cause: Mismatched JWT uri Claim with Query Parameters
The JWT payload's uri field must exactly match the full path (including query parameters and their order) of the request you're sending. Coinbase's signature validation checks this string against the actual request URI, and even minor differences (like parameter order or encoding) will trigger a 401.
Looking at your code:
- When you construct
full = f"{path}{q}", you're usingurlencode(params)which sorts parameters alphabetically by default. - But the
next_urireturned by Coinbase might have parameters in a different order, or your manual parameter construction might not match the exact encoding Coinbase expects.
Fix Suggestion:
Instead of building the URI string manually, use the exact path/query from the next_uri when constructing your JWT payload. Modify your auth_get function to handle full paths directly:
def auth_get(full_path, params=None): # Build request path with params if provided, else use the full path as-is if params: q = "?" + urlencode(params, doseq=True) request_path = f"{full_path}{q}" else: request_path = full_path now = int(time.time()) payload = { "sub": key_name, "iss": "cdp", "nbf": now, "exp": now + 120, "uri": f"GET api.coinbase.com{request_path}", # Exact match to the request path } headers = { "kid": key_name, "nonce": secrets.token_hex(16), } token = jwt.encode(payload, private_key, algorithm="ES256", headers=headers) # Split path and params for the requests.get call if needed if "?" in request_path: path, query = request_path.split("?", 1) params = dict(parse_qsl(query)) else: path = request_path params = None return requests.get( "https://api.coinbase.com" + path, headers={"Authorization": f"Bearer {token}"}, params=params, timeout=30, )
When using the next_uri:
next_uri = r1.json()["pagination"]["next_uri"] # Pass the next_uri directly (it already includes the path and query params) r2 = auth_get(next_uri)
This ensures the uri claim in your JWT exactly matches the request Coinbase receives.
2. CDP Key Permissions or API Limitations
CDP keys are designed for institutional/automated use cases, but they might have restricted access to certain V2 API features:
- Check your CDP key's permissions in the Coinbase CDP Console: Ensure it has the
wallet:transactions:readpermission (or equivalent) enabled for all relevant accounts. - Some V2 endpoints (especially paginated transaction data) might require user context that CDP keys don't provide by default. Coinbase's documentation notes that certain user-specific data may only be accessible via OAuth 2.0 user tokens, not CDP API keys.
3. Test with OAuth 2.0 User Tokens
To rule out CDP key limitations, try calling the paginated transactions endpoint using a user-level OAuth 2.0 access token. If this works, it confirms the issue is related to CDP key compatibility with that endpoint's pagination feature.
Bonus: Incomplete Accounts List Issue
The fact that GET /v2/accounts returns an incomplete list but individual account calls work is likely another permission issue. CDP keys may only be granted access to specific accounts, so double-check your key's account associations in the CDP Console.
内容的提问来源于stack exchange,提问作者Sobo

