如何使用Node.js刷新QuickBooks的OAuth2访问令牌
QuickBooks OAuth2访问令牌自动刷新解决方案
核心实现逻辑
node-quickbooks库已经内置了OAuth2令牌刷新的方法refreshAccessToken(),你只需要补充令牌持久化存储、过期自动触发刷新、刷新后重试业务逻辑三部分代码即可解决问题。
具体实现步骤
- 新增令牌持久化存储
你需要把accessToken和refreshToken从硬编码改为动态存储(示例用本地JSON文件演示,生产环境可替换为数据库、密钥管理服务等),首先在项目根目录新建tokens.json,写入初始令牌:
{ "accessToken": "你当前的有效accessToken", "refreshToken": "你当前的有效refreshToken" }
- 调整代码补充自动刷新逻辑
修改后的完整代码如下:
const QuickBooks = require("node-quickbooks"); const fs = require('fs/promises'); const path = require('path'); // 配置参数 const clientId = "你的clientId"; const clientSecret = "你的clientSecret"; const redirectUri = "你的redirectUri"; const realmId = "你的realmId"; const isSandbox = true; const debugMode = true; // 令牌存储路径 const TOKEN_PATH = path.join(__dirname, 'tokens.json'); // 读取令牌 async function loadTokens() { const tokenContent = await fs.readFile(TOKEN_PATH, 'utf8'); return JSON.parse(tokenContent); } // 保存新令牌 async function saveTokens(tokens) { await fs.writeFile(TOKEN_PATH, JSON.stringify(tokens, null, 2)); } // 初始化QBO实例 async function initQbo() { const tokens = await loadTokens(); return new QuickBooks( clientId, clientSecret, tokens.accessToken, false, realmId, isSandbox, debugMode, null, "2.0", tokens.refreshToken ); } // 刷新令牌并更新QBO实例 async function refreshQboToken(qbo) { return new Promise((resolve, reject) => { qbo.refreshAccessToken((err, newToken) => { if (err) return reject(err); // 更新QBO实例的令牌属性 qbo.accessToken = newToken.access_token; qbo.refreshToken = newToken.refresh_token; // 持久化存储新令牌 saveTokens({ accessToken: newToken.access_token, refreshToken: newToken.refresh_token }).then(() => resolve(qbo)).catch(reject); }); }); } // 业务逻辑:创建发票 async function createInvoice(qbo) { const quickbooksID = "59"; return new Promise((resolve, reject) => { qbo.getCustomer(quickbooksID, (err, customer) => { if (err) return reject(err); qbo.getItem('19', (err, item) => { if (err) return reject(err); qbo.createInvoice({ "Line": [ { "DetailType": "SalesItemLineDetail", "Amount": 32.0, "SalesItemLineDetail": { "ItemRef": { "name": item.Name, "value": item.Id }, "Qty": 5.0 } } ], "CustomerRef": { "value": customer.Id, "name": customer.DisplayName } }, (err, invoice) => { if (err) return reject(err); resolve(invoice); }) }) }) }); } // 主执行逻辑:自动处理令牌过期重试 async function main() { let qbo = await initQbo(); try { const invoice = await createInvoice(qbo); console.log('发票创建成功', invoice); } catch (err) { // 判断是否是令牌过期错误 const isTokenExpired = err?.error?.[0]?.code === '3200' || err?.statusCode === 401; if (isTokenExpired) { console.log('令牌过期,正在自动刷新...'); try { qbo = await refreshQboToken(qbo); const invoice = await createInvoice(qbo); console.log('令牌刷新成功,发票创建成功', invoice); } catch (refreshErr) { console.error('令牌刷新失败,请重新授权', refreshErr); } } else { console.error('业务执行错误', err); } } } main();
注意事项
- 生产环境不要使用本地JSON文件存储敏感令牌,建议使用密钥管理服务、加密数据库存储
- QuickBooks的refresh token有效期为101天,只要你每次刷新后都保存新的refresh token,就可以无限次续期,不需要手动获取
- 如果刷新失败,说明refresh token也已过期,需要重新到QuickBooks OAuth playground走一次授权流程获取新的令牌对,写入
tokens.json即可恢复使用
内容的提问来源于stack exchange,提问作者Erick Eaton
相关产品推荐
相关产品推荐

