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

如何使用Node.js刷新QuickBooks的OAuth2访问令牌

QuickBooks OAuth2访问令牌自动刷新解决方案

核心实现逻辑

node-quickbooks库已经内置了OAuth2令牌刷新的方法refreshAccessToken(),你只需要补充令牌持久化存储、过期自动触发刷新、刷新后重试业务逻辑三部分代码即可解决问题。

具体实现步骤

  1. 新增令牌持久化存储
    你需要把accessToken和refreshToken从硬编码改为动态存储(示例用本地JSON文件演示,生产环境可替换为数据库、密钥管理服务等),首先在项目根目录新建tokens.json,写入初始令牌:
{
  "accessToken": "你当前的有效accessToken",
  "refreshToken": "你当前的有效refreshToken"
}
  1. 调整代码补充自动刷新逻辑
    修改后的完整代码如下:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:06:00