【发布时间】: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