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

Java/JJWT为Office 365 OAuth客户端凭据签名JWT时遇签名无效错误

解决JJWT生成证书签名JWT时的"Client assertion contains an invalid signature"错误

我之前帮不少开发者排查过这个问题,这个错误基本上都是JWT签名环节的某个细节没符合微软Azure AD的严格要求,咱们一步步来定位解决:

1. 先确认证书和私钥加载是否正确

很多时候问题出在证书加载上——要么密码错了,要么没拿到正确的私钥,或者证书格式不对。

比如加载PFX格式证书的正确姿势应该是这样的(Java代码):

KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (InputStream is = new FileInputStream("your-certificate.pfx")) {
    // 这里的密码是PFX文件的保护密码
    keyStore.load(is, "your-pfx-password".toCharArray());
}
// 注意:别名要和PFX里的一致,不确定的话用keytool命令查看
String alias = "your-cert-alias"; 
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, "your-pfx-password".toCharArray());
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);

如果不知道证书别名,打开终端用这个命令查看:

keytool -list -v -keystore your-certificate.pfx -storetype pkcs12

输出里的Alias name就是你要填的别名。

2. 严格匹配微软要求的JWT声明

Azure AD对客户端断言的JWT有硬性要求,少一个字段或者填错都不行,必须包含这些:

  • iss: 你的Azure AD应用的Client ID
  • sub: 和iss完全一致,也是Client ID
  • aud: 微软令牌端点的完整URL,比如v2端点是https://login.microsoftonline.com/{你的租户ID}/oauth2/v2.0/token,v1端点是https://login.microsoftonline.com/{你的租户ID}/oauth2/token,别搞混版本
  • exp: 过期时间,不能超过1小时,建议设为当前时间+30分钟
  • nbf: 生效时间,一般设为当前时间
  • jti: 随机生成的唯一字符串,用来防止重放攻击

用JJWT构建的示例代码:

String clientId = "your-client-id";
String tenantId = "your-tenant-id";
String tokenEndpoint = String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId);

String jwtAssertion = Jwts.builder()
    .setIssuer(clientId)
    .setSubject(clientId)
    .setAudience(tokenEndpoint)
    .setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000)) // 30分钟后过期
    .setNotBefore(new Date(System.currentTimeMillis()))
    .setId(UUID.randomUUID().toString()) // 唯一ID
    .signWith(privateKey, SignatureAlgorithm.RS256) // 必须用RS256算法!
    .compact();

⚠️ 重点:签名算法必须是RS256,微软不支持HS256用于证书类型的客户端断言,别选错了。

3. 验证生成的JWT是否合法

把生成的JWT字符串拿到jwt.io上(本地解析就行,不用上传任何数据),检查这几点:

  • 头部的alg字段是不是RS256
  • 声明部分的所有字段是否和你设置的一致,特别是aud的URL要完全匹配令牌端点
  • 用你的公钥(从PFX里导出或者Azure门户里的公钥)验证签名,如果本地都验证不通过,那肯定是私钥加载或者签名过程的问题

4. 检查Azure AD应用的配置

别漏了Azure门户里的配置:

  • 你的应用已经上传了对应的公钥证书(要确保是和你签名用的私钥配对的公钥)
  • 客户端凭据流已经启用,并且你申请的Graph API权限(比如Calendars.Read)已经获得了管理员同意
  • 不要混用v1和v2端点:如果你的应用是v2版本,就用v2的令牌端点,v1同理,aud字段要和端点对应

5. 确认JJWT版本的兼容性

旧版本的JJWT可能在RS256签名的实现上有兼容性问题,建议用0.11.5及以上的版本。Maven依赖示例:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

按这个顺序排查下来,基本上就能解决签名无效的问题了。

内容的提问来源于stack exchange,提问作者Jon Moore

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:42:39