【问题标题】:Node.js, Docusign, and Heroku "errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"The access token provided is expired, revoked or malformed."Node.js、Docusign 和 Heroku "errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"提供的访问令牌已过期、撤销或格式错误。"
【发布时间】:2021-02-03 05:35:43
【问题描述】:

我目前正在将 JWT 身份验证流程用于 docusign api。一切都在本地工作,但在部署到 Heroku 时不起作用。要点是有一个由 Copper CRM 触发的 webhook,然后生成一个 JWT,该 JWT 被交易为访问令牌,以进行 api 调用以执行一些工作以查找正确的模板并发送信封。我注销了生成的访问令牌,并且在 POSTMAN 中进行相同的 API 调用可以正常工作,但是通过 heroku 进行的 api 调用给出了错误:

"errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"提供的访问令牌已过期、被撤销或格式错误。"

以下是生成 JWT 并发出请求以获取访问令牌的代码:

import jwt from 'jsonwebtoken';
import request from 'superagent';

export const createJWT = async() => {
    const iat = new Date().getTime() / 1000;
    const exp = new Date().setDate(new Date().getDate() + 2) / 1000;
    return jwt.sign({
        iss: process.env.DOCUSIGN_INTEGRATION_KEY,
        sub: process.env.DOCUSIGN_API_USERNAME,
        iat: iat,
        exp: exp,
        aud: 'account-d.docusign.com',
        scope: 'signature impersonation'
    },
        process.env.DOCUSIGN_PRIVATE_KEY,
        {
            algorithm: 'RS256'
        });
};

export const getAccessTokenFromJWT = async(jwt) => {
    const res = await request.post(`https://account-d.docusign.com/oauth/token?grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${jwt}`)
      .catch(err => console.log(err));
    return res.body.access_token;
};

这是 webhook 进行的第一个 api 调用的代码 - 给出错误的那个。

import request from 'superagent';
import dotenv from 'dotenv';

dotenv.config();

export const findTemplateIdByCohortName = async (cohortName, access_token) => {
    const url = `${process.env.DOCUSIGN_BASE_PATH}/v2.1/accounts/${process.env.DOCUSIGN_ACCOUNT_ID}/templates?search_text=${cohortName}`;
    const result = await request.get(url)
      .set({
          Authorization: `Bearer ${access_token}`
      });
    if(result.body.envelopeTemplates) {
        return result.body.envelopeTemplates[0].templateId;
    } else {
        return null;
    }
};

这是处理 webhook 的路由(我使用的是模块导入语法):

import express from 'express';
import { useTemplate } from '../request/docusign/docusign-methods.mjs';
import opportunities from '../request/prosperworks/opportunities.mjs';
import people from '../request/prosperworks/people.js';
import customFields from '../request/prosperworks/custom-fields.mjs';
import { findTemplateIdByCohortName } from '../request/docusign/templates.mjs';
import { findSentEnvelopesByStudentEmail, voidEnvelope, findTemplateFromEnvelopeTemplateUri } from '../request/docusign/envelopes.mjs';
import { createJWT, getAccessTokenFromJWT } from '../request/docusign/token.mjs';

const router = express.Router();

export default router
  .post('/copper/opportunity/updated', express.json(), async (req, res, next) => {
      const { body } = req;
      console.log('webhook received', body);
      const jwt = await createJWT();
      const access_token = await getAccessTokenFromJWT(jwt);
      console.log(access_token);
      if(!Object.keys(body.updated_attributes).length) return res.send('irrelevant webhook');
      if(body.updated_attributes.custom_fields['94620'] || body.updated_attributes.stage[0] === 'Interview Scheduled' && body.updated_attributes.stage[1] === 'Accepted') {
          try {
              const opportunity = await opportunities.get(body.ids[0]);
              const cohortId = opportunity.custom_fields.find(field => field.custom_field_definition_id === 94620).value;
              const cohortName = customFields.getCohortNameById(cohortId);
              const templateId = await findTemplateIdByCohortName(cohortName);    
              const person = await people.findById(opportunity.primary_contact_id);
              const email = person.emails[0].email;
              const { name } = person;
              const sentEnvelopes = await findSentEnvelopesByStudentEmail(email, access_token);
              await Promise.all(
                sentEnvelopes.filter(envelope => {
                    return envelope.emailSubject.includes('Enrollment Agreement');
                })
                .map(envelope => {
                    if(envelope.status === 'sent') return voidEnvelope(envelope.id, access_token);
                })
              );
              const sentEnvelopesTemplates = await Promise.all(sentEnvelopes.map(envelope => {
                  return findTemplateFromEnvelopeTemplateUri(envelope.templatesUri, access_token);
              }));
              const templateAlreadyUsedCheck = sentEnvelopesTemplates.reduce((outerAcc, templateArr) => {
                  if(templateArr.reduce((innerAcc, template) => {
                      if(template.templateId === templateId) innerAcc=true;
                      return innerAcc;
                  }, false)) {
                      outerAcc=true;
                  }
                  return outerAcc;
              }, false);
              console.log(templateAlreadyUsedCheck);
              if(templateAlreadyUsedCheck) return res.send('envelope already sent');
              const envelope = await useTemplate({
                  basePath: process.env.DOCUSIGN_BASE_PATH,
                  accessToken: access_token,
                  accountId: process.env.DOCUSIGN_ACCOUNT_ID,
                  envelopeArgs: {
                      templateId: templateId,
                      signerEmail: email,
                      signerName: name
                  }
              });  
              return res.send(envelope);
          }
          catch(err) {
              console.log(err);
              next(err);
          }
      } else {
          return res.send('irrelevant webhook');
      }
  });

【问题讨论】:

    标签: node.js heroku jwt docusignapi


    【解决方案1】:

    关于这个的几个问题:

    1. 在本地和 Heroku 上尝试此操作时,您是否使用相同的集成密钥?
    2. 我注意到你的环境被硬编码为aud: 'account-d.docusign.com'。您的意思是在本地和 Heroku 中都使用演示环境吗?

    我的理解是,当您在 Postman 上本地运行时,所有这些都可以正常工作,但在 Heroku 中部署后,您会看到授权错误。我的理解准确吗?

    谢谢!

    【讨论】:

      【解决方案2】:

      原来问题在于我没有将 access_token 传递给进行 api 调用的函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-26
        • 1970-01-01
        • 2016-04-10
        相关资源
        最近更新 更多