PHP调用Coinbase高级交易API:JWT鉴权返回NULL问题排查
PHP调用Coinbase高级交易API返回NULL问题排查
我尝试用PHP调用Coinbase高级交易API,该API采用JWT鉴权,但官方未提供PHP示例。自行编写代码后,调用接口返回NULL,已多次核对API密钥信息确认无误。
原代码
use Firebase\JWT\JWT; $keyName = 'organizations/b0f974e{redacted}860/apiKeys/d840f8{redacted}b6d'; $keySecret = "-----BEGIN EC PRIVATE KEY----- MHcC{redacted}bHEzMVwDhg== -----END EC PRIVATE KEY----- "; $requestMethod = "GET"; $requestHost = "api.coinbase.com"; $requestPath = "/api/v3/brokerage/accounts"; function buildJwt($uri, $keyName, $keySecret) { $privateKeyResource = openssl_pkey_get_private($keySecret); if (!$privateKeyResource) { throw new Exception('Private key could not be parsed or is invalid.'); } $payload = [ 'sub' => $keyName, 'iss' => 'coinbase-cloud', 'iat' => time(), 'exp' => time() + 120, // Token expiration time (example: 120 seconds from now) 'uri' => $uri, ]; $jwt = JWT::encode($payload, $privateKeyResource, 'ES256'); return $jwt; } function main($requestMethod, $requestHost, $requestPath, $keyName, $keySecret) { $uri = "$requestMethod $requestHost$requestPath"; $jwtToken = buildJwt($uri, $keyName, $keySecret); return $jwtToken; } $myjwt = main($requestMethod, $requestHost, $requestPath, $keyName, $keySecret); function getAccountDetails($jwt, $requestMethod, $requestHost, $requestPath) { $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://$requestHost$requestPath", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => $requestMethod, CURLOPT_HTTPHEADER => [ "Authorization: Bearer $jwt", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #:" . $err; } else { return json_decode($response, true); } } $res = getAccountDetails($myjwt, $requestMethod, $requestHost, $requestPath); var_dump($res);
问题排查与修复方案
1. JWT的URI格式错误
Coinbase要求JWT payload中的uri字段格式为请求方法 路径,不需要包含host。原代码中拼接了$requestHost,导致URI格式不符合要求,这是核心问题。
2. 缺少HTTP状态码与原始响应排查
原代码仅捕获cURL错误,但API返回非200状态码时,json_decode可能返回NULL,无法定位具体错误原因。
3. 私钥格式隐患
双引号包裹私钥可能导致转义问题,建议改用单引号。
修复后的代码
use Firebase\JWT\JWT; $keyName = 'organizations/b0f974e{redacted}860/apiKeys/d840f8{redacted}b6d'; $keySecret = '-----BEGIN EC PRIVATE KEY----- MHcC{redacted}bHEzMVwDhg== -----END EC PRIVATE KEY-----'; $requestMethod = "GET"; $requestHost = "api.coinbase.com"; $requestPath = "/api/v3/brokerage/accounts"; function buildJwt($uri, $keyName, $keySecret) { $privateKeyResource = openssl_pkey_get_private($keySecret); if (!$privateKeyResource) { throw new Exception('私钥解析失败或无效'); } $payload = [ 'sub' => $keyName, 'iss' => 'coinbase-cloud', 'iat' => time(), 'exp' => time() + 120, // Token有效期120秒 'uri' => $uri, ]; $jwt = JWT::encode($payload, $privateKeyResource, 'ES256'); return $jwt; } function main($requestMethod, $requestPath, $keyName, $keySecret) { // 修正URI格式:仅包含请求方法和路径 $uri = "$requestMethod $requestPath"; $jwtToken = buildJwt($uri, $keyName, $keySecret); return $jwtToken; } $myjwt = main($requestMethod, $requestPath, $keyName, $keySecret); function getAccountDetails($jwt, $requestMethod, $requestHost, $requestPath) { $url = "https://$requestHost$requestPath"; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => $requestMethod, CURLOPT_HTTPHEADER => [ "Authorization: Bearer $jwt", "Content-Type: application/json" ], ]); $response = curl_exec($curl); $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); // 获取HTTP状态码 $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL错误: " . $err; return null; } else { // 打印状态码和原始响应,方便排查 echo "HTTP状态码: $httpCode\n"; echo "原始响应: $response\n"; return json_decode($response, true); } } $res = getAccountDetails($myjwt, $requestMethod, $requestHost, $requestPath); var_dump($res);
额外排查点
- 确认服务器时间与标准时间同步,JWT的
iat/exp字段依赖准确时间,偏差过大会导致Token验证失败。 - 检查API密钥是否拥有
accounts:read权限,权限不足也会返回错误。
内容的提问来源于stack exchange,提问作者Dan Holt
相关产品推荐
相关产品推荐

