JS调用API获取token报401签名不匹配错误如何排查修复
OAuth 1.0接口401 Signature mismatch错误排查与修复
错误基础信息
- 接口返回状态码:
401 Unauthorized - 错误提示:
Signature mismatch. Authorization signature or client credential is wrong. - 请求携带的Authorization头内容:
OAuth oauth_consumer_key="V3R6bm******DznqE-ellA", oauth_nonce="bbo8dYK6anE6JZsEIhj2RmKuEwV0****", oauth_signature="UQH1OnFWEscFbyZIx4DRn9qSOW+nvIlzCEgXrjm***=", oauth_signature_method="HMAC-SHA256", oauth_timestamp="1654152360", oauth_version="1.0"
- 报错参考截图:

排查思路(按问题出现概率从高到低排序)
- 检查签名密钥拼接规则
你使用的是HMAC-SHA256签名算法,密钥固定拼接规则为RFC3986编码后的consumer_secret&:获取token阶段还没有生成token_secret,末尾的&必须保留,不能直接用consumer_secret作为密钥计算签名,这是手写签名逻辑最高发的错误。如果是已获取access_token后的请求,需要在&后拼接RFC3986编码后的token_secret。 - 检查签名基串生成规则
OAuth1.0的签名基串结构必须严格为大写请求方法&编码后的请求根路径&编码后的排序参数字符串,三部分用单个&连接:- 请求方法必须全大写,例如
POST/GET,不能用小写 - 请求根路径不能携带query参数,必须是scheme+host+path的完整路径,例如
https://api.example.com/oauth/token - 参与签名的参数包含所有
oauth_开头的参数(除realm外)、URL query参数、POST表单类型的请求体参数,所有参数先单独做RFC3986编码,再按参数名字典序升序排列,用=连接键值、&连接多个键值对拼成参数字符串,最后对整个参数字符串再做一次RFC3986编码,放入基串的第三部分 - 注意JS原生
encodeURIComponent不符合RFC3986编码要求,不会对!,*,(,),'字符做编码,直接使用会导致基串计算错误
- 请求方法必须全大写,例如
- 检查参数合法性
- 确认
oauth_consumer_key和对应consumer_secret为当前环境的有效凭证,没有复制时多带空格、漏字符,不要混用测试环境和生产环境凭证 - 确认
oauth_timestamp为请求发起时刻的秒级Unix时间戳,你当前请求头里的时间戳1654152360对应时间为2022-06-02,和当前时间差超过服务端允许的5分钟误差范围,大概率是硬编码了旧请求的时间戳,没有动态生成当前时间戳,时间偏差过大会直接被判定签名无效 - 确认
oauth_nonce为每次请求生成的唯一随机字符串,不要重复使用历史请求的nonce值
- 确认
- 检查签名结果处理逻辑
HMAC-SHA256计算出的二进制结果必须先做Base64编码,再做RFC3986编码后才能放入Authorization头,注意JS原生btoa方法处理非ASCII字符会出现乱码,不要直接用其处理签名二进制结果。 - 检查Authorization头格式
所有参数值必须用英文双引号包裹,参数之间用英文逗号加空格分隔,不要使用单引号,不要夹带不可见字符、多余空格,你当前提供的头格式符合基础规范,但需要确认代码生成时没有引入隐藏字符。
快速修复建议
生产环境不要手写完整的OAuth1.0签名逻辑,边界case极多,直接使用经过社区验证的开源库(例如
oauth-1.0a)实现签名流程即可避免90%以上的签名错误。
定位问题时可以用相同的参数、密钥、请求地址,通过成熟库生成签名,和你自己代码生成的签名逐环节对比(密钥、基串、编码结果),很快就能定位到错误点。
内容的提问来源于stack exchange,提问作者VDT
相关产品推荐
相关产品推荐

