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

调用DocuSign createEnvelope时JWT令牌返回401 AUTHORIZATION_INVALID_TOKEN

DocuSign AUTHORIZATION_INVALID_TOKEN 错误排查

我通过以下代码获取DocuSign访问令牌:

import * as docusign from 'docusign-esign';

const expiresIn = 28800;

export const createClient = async (): Promise<docusign.ApiClient> => {
  const apiClient = new docusign.ApiClient({ basePath: process.env.BASE_PATH, oAuthBasePath: process.env.O_AUTH_BASE_PATH });

  try {
    const response = await apiClient.requestJWTApplicationToken(
      process.env.CLIENT_ID,
      ["signature", "impersonation"],
      Buffer.from(process.env.RSA_PRIVATE_KEY.replace(/\\n/g, '\n')),
      expiresIn
    );

    console.log(response.body.access_token) // -> 成功返回访问令牌

    apiClient.addDefaultHeader("Authorization", "Bearer " + response.body.access_token);
  } catch (error){ throw AppError("自定义错误") }

  return apiClient;
}

随后在另一处编写了创建信封的函数:

import { EnvelopeDefinition, EnvelopeRecipients, EnvelopesApi, Signer } from 'docusign-esign';
import { createClient } from "./above-file-path.ts";

export const someFunction = async () => {
  const signer1: Signer = { email: 'my-personal-email-for-testing@gmail.com', name: '我的名字', roleName: '我的名字' };
  const signer2: Signer = { email: 'client@gmail.com', name: '客户名字', roleName: 'Client' };

  const recipients: EnvelopeRecipients = { signers: [signer1, signer2] };

  const dsApiClient = await createClient();

  const envelope: EnvelopeDefinition = {
    emailSubject: '请签署这份协议',
    templateId: '我的模板UUID',
    status: 'created',
    recipients,
  };

  const envelopesApi = new EnvelopesApi(dsApiClient);

  try {
    const { envelopeId, errorDetails } = await envelopesApi.createEnvelope(process.env.ACCOUNT_ID, {
      envelopeDefinition: envelope,
    });

    console.log("是否成功?: ", envelopeId)
  } catch (error) {
    console.log(error) // -> 返回错误:Unauthorized...{"errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"提供的访问令牌已过期、被吊销或格式错误。系统应用程序认证失败。"}
  }
}

调用该函数时持续收到AUTHORIZATION_INVALID_TOKEN错误。

补充信息:

  • 获取令牌后立即调用函数,确认令牌未过期;
  • O_AUTH_BASE_PATH使用account-d.docusign.com,BASE_PATH使用https://demo.docusign.net/restapi。

可能的原因及解决方案

1. 缺少用户模拟(Impersonation)步骤

你当前用requestJWTApplicationToken生成的是应用级令牌,无法直接代表特定用户执行创建信封这类需要用户上下文的操作,必须完成用户模拟:

修改createClient函数,添加用户信息获取与账户配置步骤:

export const createClient = async (): Promise<docusign.ApiClient> => {
  const apiClient = new docusign.ApiClient({ basePath: process.env.BASE_PATH, oAuthBasePath: process.env.O_AUTH_BASE_PATH });

  try {
    const response = await apiClient.requestJWTApplicationToken(
      process.env.CLIENT_ID,
      ["signature", "impersonation"],
      Buffer.from(process.env.RSA_PRIVATE_KEY.replace(/\\n/g, '\n')),
      expiresIn
    );

    const accessToken = response.body.access_token;
    console.log(accessToken)

    // 新增:获取用户信息,完成模拟
    const userInfo = await apiClient.getUserInfo(accessToken);
    // 选择默认账户(多账户场景可按需筛选)
    const targetAccount = userInfo.accounts.find(acc => acc.isDefault);
    if (!targetAccount) throw new Error("未找到目标账户");

    // 更新apiClient的basePath为当前账户的专属路径
    apiClient.setBasePath(`${targetAccount.baseUri}/restapi`);
    // 重新设置授权头
    apiClient.addDefaultHeader("Authorization", `Bearer ${accessToken}`);
    // 同步正确的账户ID到环境变量
    process.env.ACCOUNT_ID = targetAccount.accountId;
  } catch (error){ throw new Error(`自定义错误: ${(error as Error).message}`) }

  return apiClient;
}

2. 账户ID与模板不匹配

  • 确保process.env.ACCOUNT_ID是模拟后获取的正确账户ID,而非硬编码的错误值;
  • 验证templateId对应的模板确实存在于当前使用的演示环境账户中。

3. RSA密钥格式验证

检查RSA_PRIVATE_KEY环境变量的换行符处理是否正确,转换后的私钥需完整无缺失,可在代码中打印转换后的密钥内容确认格式。

4. 应用权限确认

登录DocuSign开发者后台,确认你的应用已启用signature和impersonation权限,且JWT请求中正确传递了这两个权限范围。

内容的提问来源于stack exchange,提问作者Rubek Joshi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 16:02:03