You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Coinbase读取账户余额?遭遇401无效签名错误求助

解决Coinbase API获取账户时的401无效签名问题

看起来你已经搞定了价格查询的部分,但调用账户接口时的签名生成出了几个关键问题,导致了invalid signature错误。我帮你梳理一下问题点和修复方案:

核心问题分析

Coinbase API的签名规则要求每个请求的签名必须基于timestamp + HTTP方法 + 请求路径(含查询参数) + 请求体的拼接字符串,你的代码在调用账户接口时违反了这个规则:

  • 签名消息缺少时间戳:你生成账户请求的签名时,message只写了"GET/v2/accounts",但必须把当前请求的Unix时间戳加在最前面,和价格请求的格式保持一致。
  • 复用旧的时间戳:两次请求用了同一个unixTimestamp,Coinbase要求每个请求的时间戳必须是当前的(且与服务器时间差不超过30秒),复用旧时间戳会直接导致签名验证失败。
  • 多余的查询参数:/v2/accounts接口不需要currency查询参数,你额外添加的这个参数会让实际请求路径和签名计算的路径不匹配,进而触发签名错误。
  • 重复使用HMAC实例:同一个HMACSHA256实例在多次调用ComputeHash后可能出现状态异常,建议每次请求都创建新的实例。

修正后的代码

下面是修复后的完整代码,我标注了关键修改点:

using System;
using System.Text;
using System.Security.Cryptography;
using Flurl;
using Flurl.Http;
using Newtonsoft.Json;
using System.Net;

namespace demibyte.coinbase
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            var host = "https://api.coinbase.com/";
            var apiKey = "my api key";
            var apiSecret = "my api secret";
            var currency = "AUD";
            var apiVersion = "2016-03-03"; // 确保这个值和Coinbase API设置页面的版本一致

            // --- 价格请求部分(保留原逻辑,没问题) ---
            var priceTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
            var priceMessage = $"{priceTimestamp}GET/v2/prices/spot?currency={currency}";
            byte[] priceSecretKey = Encoding.UTF8.GetBytes(apiSecret);
            using (HMACSHA256 priceHmac = new HMACSHA256(priceSecretKey))
            {
                byte[] priceBytes = Encoding.UTF8.GetBytes(priceMessage);
                byte[] priceRawHmac = priceHmac.ComputeHash(priceBytes);
                var priceSignature = priceRawHmac.ByteArrayToHexString();

                var price = host
                    .AppendPathSegment("v2/prices/spot")
                    .SetQueryParam("currency", currency)
                    .WithHeader("CB-ACCESS-SIGN", priceSignature)
                    .WithHeader("CB-ACCESS-TIMESTAMP", priceTimestamp)
                    .WithHeader("CB-ACCESS-KEY", apiKey)
                    .WithHeader("CB-VERSION", apiVersion)
                    .GetJsonAsync<dynamic>()
                    .Result;

                Console.WriteLine(price.ToString(Formatting.None));
                Console.WriteLine();
            }

            // --- 账户请求部分(修复后的逻辑) ---
            // 1. 生成新的当前时间戳,不能复用之前的
            var accountTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
            // 2. 签名消息必须包含时间戳 + 方法 + 请求路径(这里没有查询参数,所以直接写/v2/accounts)
            var accountMessage = $"{accountTimestamp}GET/v2/accounts";
            byte[] accountSecretKey = Encoding.UTF8.GetBytes(apiSecret);
            // 3. 每次请求创建新的HMAC实例,避免状态异常
            using (HMACSHA256 accountHmac = new HMACSHA256(accountSecretKey))
            {
                byte[] accountBytes = Encoding.UTF8.GetBytes(accountMessage);
                byte[] accountRawHmac = accountHmac.ComputeHash(accountBytes);
                var accountSignature = accountRawHmac.ByteArrayToHexString();

                var accounts = host
                    .AppendPathSegment("v2/accounts")
                    // 4. 移除多余的currency查询参数,/v2/accounts不需要这个
                    .WithHeader("CB-ACCESS-SIGN", accountSignature)
                    .WithHeader("CB-ACCESS-TIMESTAMP", accountTimestamp)
                    .WithHeader("CB-ACCESS-KEY", apiKey)
                    .WithHeader("CB-VERSION", apiVersion)
                    .GetJsonAsync<dynamic>()
                    .Result;

                Console.WriteLine(accounts.ToString(Formatting.None));
                Console.ReadLine();
            }
        }
    }
}

额外注意事项

  • 确保你的API密钥已经启用了wallet:accounts:read权限(你已经提到这一点,没问题)。
  • 如果还是遇到时间相关的错误,可以先对比本地时间和Coinbase服务器时间,确保时间差在30秒以内。
  • 建议使用async/await替代.Result来避免死锁问题,尤其是在非控制台应用中。

内容的提问来源于stack exchange,提问作者Nick_F

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:09:37