Spring Boot资源服务器报错:JOSE header typ(JOSE)不被允许
问题:Spring Boot资源服务器拒绝公司授权服务器的ID Token,提示JOSE头部typ不允许
问题背景
- 架构:Spring Boot OAuth客户端 + Angular前端 + Spring Boot资源服务器
- 认证流程:Angular发起OAuth认证 → 重定向至公司授权服务器 → 授权完成后携带code返回Angular → Angular将code传给Spring Boot客户端 → 客户端返回access token、ID token等凭证
- 异常表现:对接Google授权服务器时,用ID Token作为Bearer Token访问资源服务器正常;但使用公司授权服务器的Token访问时,返回未授权响应,错误信息:
Bearer error="invalid_token", error_description="An error occurred while attempting to decode the Jwt: JOSE header typ (type) JOSE not allowed"
- 资源服务器日志:
o.s.s.o.s.r.a.JwtAuthenticationProvider [ajp-nio-8009-exec-399] Failed to authenticate since the JWT was invalid
排查结论
问题根源在于公司授权服务器返回的ID Token头部typ字段值为JOSE,而非标准的JWT:
{ "alg": "RS256", "typ": "JOSE" }
当前配置
资源服务器配置类
@Configuration public class ResourceServerConfig { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String issuerUri; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests(authorizeRequests -> authorizeRequests .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(Customizer.withDefaults())); return http.build(); } }
应用配置属性
spring.security.oauth2.resourceserver.jwt.issuer-uri={COMPANY_AUTH} spring.security.oauth2.resourceserver.jwt.jwk-set-uri={COMPANY_AUTH}/jwk
注:{COMPANY_AUTH}与ID Token中的iss字段一致,使用Spring Boot v2.6.7。
解决方案
Spring Security默认仅允许JWT头部typ字段值为JWT或不指定,要兼容JOSE值,需自定义JWT解码器,放宽typ字段的校验逻辑:
方案1:允许JOSE和JWT两种typ值
修改资源服务器配置类,自定义JwtDecoder Bean:
@Configuration public class ResourceServerConfig { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String issuerUri; @Bean public JwtDecoder jwtDecoder() { return NimbusJwtDecoder.withIssuerLocation(issuerUri) .jwtProcessorCustomizer(jwtProcessor -> { ConfigurableJWTProcessor<SecurityContext> processor = (ConfigurableJWTProcessor<SecurityContext>) jwtProcessor; processor.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>() { @Override public void verify(final JOSEObjectType type, final SecurityContext context) throws BadJOSEException { // 允许typ为JOSE或JWT if (!JOSEObjectType.JWT.equals(type) && !new JOSEObjectType("JOSE").equals(type)) { throw new BadJOSEException("Unsupported JWT type: " + type); } } }); }) .build(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests(authorizeRequests -> authorizeRequests .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.decoder(jwtDecoder()))); return http.build(); } }
方案2:完全跳过typ字段校验
如果不需要校验typ字段,可直接放行:
@Bean public JwtDecoder jwtDecoder() { return NimbusJwtDecoder.withIssuerLocation(issuerUri) .jwtProcessorCustomizer(jwtProcessor -> { ConfigurableJWTProcessor<SecurityContext> processor = (ConfigurableJWTProcessor<SecurityContext>) jwtProcessor; processor.setJWSTypeVerifier((type, context) -> { // 不做任何typ校验 }); }) .build(); }
说明
Spring Security底层依赖Nimbus库处理JWT,默认的DefaultJOSEObjectTypeVerifier仅允许typ为JWT,上述配置通过自定义校验逻辑实现对JOSE值的兼容,适配Spring Boot 2.6.7对应的Spring Security 5.6.x版本。
内容的提问来源于stack exchange,提问作者Thomas A Mathew
相关产品推荐
相关产品推荐

