如何解决Node.js中Axios发起OAuth1认证GET请求的401错误
问题:Axios发起OAuth1.0 GET请求返回401认证错误
在Node.js环境使用Axios调用预约应用的可用时段接口,Postman测试正常,但复制Postman生成的代码后触发401认证错误。
相关代码
app.get("/slots", (req, res) => { getAvailableSlots(res); })
const getAvailableSlots = (res) => { let config = { method: 'get', maxBodyLength: Infinity, url: '<url>&oauth_consumer_key=<key>&oauth_token=<token>&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1680087781&oauth_nonce=AKuBSQsiXz1&oauth_version=1.0&oauth_signature=nRiByohboigwEbDuqr0yDzy%2BHjw%3D', headers: { 'Cookie': 'session_id=fd65f21c120061ce905241be94d10f0fd807cf48' } }; axios.request(config) .then((response) => { res.send(JSON.stringify(response.data)); }) .catch((error) => { res.send(error); }); }
错误信息
{"message":"Request failed with status code 401","name":"AxiosError","stack":"AxiosError: Request failed with status code 401\n at settle (/Users/admin/projects/professionals-appointment-booking-widget/node_modules/axios/dist/node/axios.cjs:1900:12)\n at IncomingMessage.handleStreamEnd (/Users/admin/projects/professionals-appointment-booking-widget/node_modules/axios/dist/node/axios.cjs:2952:11)\n at IncomingMessage.emit (node:events:525:35)\n at endReadableNT (node:internal/streams/readable:1359:12)\n at process.processTicksAndRejections (node:internal/process/task_queues:82:21)","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"adapter":["xhr","http"],"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":null,"env":{},"headers":{"Accept":"application/json, text/plain, */*","Authorization":"OAuth oauth_consumer_key=\"j5r7K9FLCRbuli9w4Z4Ddyq6pnYY1ooc\",oauth_token=\"IK4BaunTMgBRk9J9wVLsUZW4eHjPZyYY\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1680087105\",oauth_nonce=\"O5XKmWv8pS6\",oauth_version=\"1.0\",oauth_signature=\"WxrQNOA9rM7mNePuju8jGoM%2BF4Y%3D\"","Cookie":"session_id=fd65f21c120061ce905241be94d10f0fd807cf48","User-Agent":"axios/1.3.4","Accept-Encoding":"gzip, compress, deflate, br"},"method":"get","url":"https://crm.cadabams.com/restapi/1.0/object/slot.booking?domain=[(%27doctor_id%27,%20%27=%27,5314),%20(%27availability%27,%20%27=%27,%20%27open%27)]&fields=[%27doctor_id%27,%20%27start_datetime%27,%20%27stop_datetime%27,%27id%27%20]"},"code":"ERR_BAD_REQUEST","status":401}
问题分析
- OAuth参数重复传递:代码中URL已携带OAuth参数,但错误日志显示Headers里同时存在
Authorization的OAuth头,导致认证逻辑冲突。 - 固定OAuth动态参数:Postman生成的
oauth_timestamp和oauth_nonce是静态值,OAuth1.0要求这两个参数每次请求都动态生成(timestamp为当前时间戳,nonce为随机字符串),固定值会直接导致签名失效。 - Cookie环境不一致:Postman中的
session_id仅适用于Postman的会话环境,Node.js请求中的Cookie可能已过期或不被服务器认可。
解决方案
1. 统一OAuth参数传递方式
移除URL中的OAuth参数,仅通过Authorization头传递认证信息,避免参数冲突:
const getAvailableSlots = (res) => { let config = { method: 'get', maxBodyLength: Infinity, url: 'https://crm.cadabams.com/restapi/1.0/object/slot.booking?domain=[(%27doctor_id%27,%20%27=%27,5314),%20(%27availability%27,%20%27=%27,%20%27open%27)]&fields=[%27doctor_id%27,%20%27start_datetime%27,%20%27stop_datetime%27,%27id%27%20]', headers: { 'Authorization': 'OAuth oauth_consumer_key="j5r7K9FLCRbuli9w4Z4Ddyq6pnYY1ooc",oauth_token="IK4BaunTMgBRk9J9wVLsUZW4eHjPZyYY",oauth_signature_method="HMAC-SHA1",oauth_timestamp="<动态时间戳>",oauth_nonce="<随机字符串>",oauth_version="1.0",oauth_signature="<动态生成的签名>"', 'Cookie': 'session_id=<有效session_id>' } }; axios.request(config) .then((response) => { res.send(JSON.stringify(response.data)); }) .catch((error) => { res.send(error); }); }
2. 动态生成OAuth1.0参数
手动生成参数易出错,推荐用oauth-1.0a库自动处理签名逻辑:
- 安装依赖:
npm install oauth-1.0a - 修改代码自动生成参数:
const OAuth = require('oauth-1.0a'); const crypto = require('crypto'); // 初始化OAuth配置 const oauth = OAuth({ consumer: { key: 'j5r7K9FLCRbuli9w4Z4Ddyq6pnYY1ooc', secret: '<你的consumer secret>' // Postman可能隐藏该密钥,需补充 }, signature_method: 'HMAC-SHA1', hash_function(base_string, key) { return crypto.createHmac('sha1', key).update(base_string).digest('base64'); } }); // 填写token信息 const token = { key: 'IK4BaunTMgBRk9J9wVLsUZW4eHjPZyYY', secret: '<你的token secret>' // 补充对应的token密钥 }; const getAvailableSlots = (res) => { const url = 'https://crm.cadabams.com/restapi/1.0/object/slot.booking'; const params = { domain: '[(\'doctor_id\', \'=\',5314), (\'availability\', \'=\', \'open\')]', fields: '[\'doctor_id\', \'start_datetime\', \'stop_datetime\',\'id\']' }; // 自动生成认证头 const authHeader = oauth.toHeader(oauth.authorize({url, method: 'GET', params}, token)); let config = { method: 'get', url: url, params: params, headers: { ...authHeader, 'Cookie': 'session_id=<有效session_id>' } }; axios.request(config) .then((response) => { res.send(JSON.stringify(response.data)); }) .catch((error) => { res.send(error); }); }
3. 验证Cookie有效性
- 检查
session_id是否在Node.js请求环境中有效,可通过浏览器访问目标接口,提取当前有效的session_id替换。 - 若接口允许,可尝试移除Cookie,确认是否仅依赖OAuth认证即可访问。
内容的提问来源于stack exchange,提问作者rehan.ankalgi
相关产品推荐
相关产品推荐

