firebase 函数与 xero-node 的集成

firebase functions integration with xero-node

正在尝试创建一个由某些数据库或 onRequest 事件触发的 firebase 函数,该函数在 Xero 上创建付款以更好地管理收到的发票。

不确定我是否理解如何从 firebase 函数 运行(如果可能的话)xero-node 库。

我一直在摆弄这两者,它似乎并不像我期望的那样用秘密 ID 初始化对象和调用函数那么简单:

const xero = new XeroClient({
  clientId: '230823jff',
  clientSecret: 'sdfh39fhsdaf',
  redirectUris: [`http://localhost:3000/xero`],
  scopes: 'openid profile email accounting.transactions offline_access'.split(' '),
})

xero.accountingApi.getInvoices('tennetid093242')

看来我需要使用以下内容生成访问密钥(12 分钟后过期):

let consentUrl = await xero.buildConsentUrl()
res.redirect(consentUrl)

在 postman 中弄乱 api,这个流程感觉我让它变得比它应该的更复杂。

有没有一种方法可以只用管理范围或其他东西初始化它而不必担心访问密钥... 或者我应该在客户端使用 xero-node ......(当然不是)

有带有 xero-node 的 expressjs 版本,所以我可以通过将 redirectUri 设置为另一个 firebase 函数的地址来获取会话密钥来做与 firebase onrequest 函数等效的事情吗?


我去的地方很慢..

我的 firebase 函数如下所示:

const xero = new XeroClient({
  clientId: '123213123123',
  clientSecret: '123123123123',
  redirectUris: ['http://localhost:5001/example/us-central1/xeroAuthCode'],
  scopes: ['openid', 'profile', 'email', 'accounting.transactions', 'accounting.settings', 'offline_access']
})

exports.xeroInit = functions.https.onRequest(async (req, res) => {
  let consentUrl = await xero.buildConsentUrl()
  res.redirect(consentUrl)
})

exports.xeroAuthCode = functions.https.onRequest(async (req, res) => {
  let tokenSet = await xero.apiCallback(req.url)
  console.log(tokenSet)
})

我的想法是调用 xeroInit 并将令牌发送到 xeroAuth 这似乎有效,因为控制台记录 req.url 给出:

/?code=c5105f6ce943....230a23fsadf&scope=openid%20profile%20email%20accounting.transactions%20accounting.settings&session_state=tFC6G9Go_zBguCjIpy8-9gl6-9SWLTlUmY5CXMq49es.3c42d9ca9e53285596193bf423f791f3

但是我在尝试设置它时遇到此错误 apiCallback

TypeError: Cannot read property 'callbackParams' of undefined

使用纯 Express 应用程序进行测试,效果非常好,我希望这是 firebase 函数模拟器的错误...

因为这与 express 一起工作,所以我在我的 firebase 函数中使用了 express 并使用 request.url 调用 apiCallback 工作...... 当我让它完全适用于想要一起使用 firebase 和 xero-node 的其他人时,我会更新答案。

编辑: 啊,我想你需要做的只是第二次初始化客户端使用:

await xero.initialize()

需要在 XeroClient

上调用以设置相关 openid-client

buildConsentUrl 还会在后台调用 await xero.initialize(),因此由于您在初始线程中调用它,因此它会正确设置客户端。由于 firebase 函数被孤立,我认为你只需要调用 initialize() fn。



您需要让您希望通过 API 与之通信的 Xero 组织的用户通过整个 OAuth2.0 流程来生成 access_token.

我推荐查看一个很好的示例应用程序,它显示了整个流程:https://github.com/XeroAPI/xero-node-oauth2-app/blob/master/src/app.ts#L172


您的目标是促进许多用户使用您的应用程序读写他们的组织吗?或者您只是想为单个组织连接和自动化东西?

如果您尝试执行第二种操作,此视频展示了如何在 REST 客户端中生成初始 access_token 并将其插入您的代码流以不断刷新。 https://www.youtube.com/watch?v=Zcf_64yreVI

非常感谢 SerKnight 帮助我在 firebase 函数上工作以供将来参考这里是我开始工作的配置。

一些笔记

  • 只是在 firebase 函数中调用 xero.initialize() 作为回调无论出于何种原因都不起作用,所以我使用 express 来处理初始设置。
  • 一旦我在数据库中有了刷新令牌,我的连接函数就会发挥魔力,所以我不需要每次调用函数时都需要 buildConsentUrl。
  • 如果你愿意,你可以继续使用 express 来调用你的函数。

确保您的 firebase 函数 url 已完整放入 xeros myapps 页面的 OAuth 2.0 redirect URIs 中,如您在我的示例中所见。 localhost if using firebase emulators

const app = express()
app.use(cors())

let x_client_id = functions.config().xero.client_id
let x_client_sectet = functions.config().xero.client_secret

const xero = new XeroClient({
  clientId: x_client_id,
  clientSecret: x_client_sectet,
  redirectUris: ['http://localhost:5001/example/us-central1/xeroInit/callback'],
  scopes: ['openid', 'profile', 'email', 'accounting.transactions', 'accounting.settings', 'offline_access'],
  httpTimeout: 3000,
  state: 123
})

const connect = () =>
  new Promise(async (res, rej) => {
    let snapshot = await db.ref('xero-config').once('value')
    let tokenSet = snapshot.val()
    try {
      xero.initialize()
      const newTokenSet = await xero.refreshWithRefreshToken(x_client_id, x_client_sectet, tokenSet.refresh_token)
      db.ref('xero-config').set(newTokenSet)
      xero.setTokenSet(newTokenSet)
      res()
    } catch (error) {
      rej(error)
    }
  })

app.get('/connect', async (req, res) => {
  try {
    await connect()
    res.send('Connection established')
  } catch (error) {
    let consentUrl = await xero.buildConsentUrl()
    res.redirect(consentUrl)
  }
})
app.get('/callback', async (req, res) => {
  let TokenSet = await xero.apiCallback(req.url)
  db.ref('xero-config').set(TokenSet)
  res.send('Token updated ')
})
exports.xeroInit = functions.https.onRequest(app)

exports.xeroOrganisation = functions.https.onRequest(async (req, res) => {
  await connect() //Doesn't handle errors and will break if inactive for 60 days but you get the idea
  await xero.updateTenants()
  res.json(xero.tenants[0])
})
  1. 使用 http://localhost:5001/example/us-central1/xeroInit/connect
  2. 调用连接函数
  3. 确保重定向后您收到 token updated 消息
  4. 调用您的 xeroOrganisation 函数以确保一切正常(: