spring-projects/spring-security · error · BadJwtException

Failed to validate the token

Error message

Failed to validate the token

What it means

createClaimsSet maps a BadJOSEException from the Nimbus JOSE+JWT processor to Spring Security's BadJwtException with message 'Failed to validate the token'. BadJOSEException indicates Nimbus rejected the token during processing: signature verification failed, the JWS algorithm is not in the allowed set, or a critical claim check failed.

Solutions

  1. Confirm jwk-set-uri/issuer-uri matches the authorization server that signed the token and that the JWK Set is reachable
  2. Check the token's alg header against decoder.setJwsAlgorithms(...); add the algorithm if it is legitimate for your deployment
  3. Regenerate/re-obtain the access token; ensure it is not truncated, re-signed, or tampered
  4. If using symmetric signing, verify the SecretKey/OctetSequenceKey matches the one the server used

Example fix

// before
NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri)
    .jwsAlgorithm(RS256::equals).build();
// after: accept the ES384 tokens your IdP issues
NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri)
    .jwsAlgorithms(algs -> { algs.add(SignatureAlgorithm.RS256); algs.add(SignatureAlgorithm.ES384); })
    .build();
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check the token's alg against the algorithms the decoder allows
String headerB64 = token.split("\\.")[0];
String alg = new String(Base64.getUrlDecoder().decode(headerB64));
boolean algAllowed = alg.contains("\"RS256\"");

Type guard

static boolean decoderSupportsAlgorithm(JWSHeader header, Set<JWSAlgorithm> allowed) {
  return header != null && allowed.contains(header.getAlgorithm());
}

Try / catch

try {
  Jwt jwt = decoder.decode(token).block();
} catch (BadJwtException ex) {
  if (ex.getCause() instanceof BadJOSEException) {
    log.debug("Signature/algorithm rejection: {}", ex.getCause().getMessage());
  }
  throw new UnauthorizedException("invalid_token");
}

Prevention

When it happens

Trigger: jwtProcessor.process(parsedToken, context) throws BadJOSEException: signature verification against the configured JWK Set/SecretKey fails, the token's alg is not in the processor's expected JWS algorithm set (e.g. 'Unsupported algorithm' / 'Algorithm not allowed'), or the JWT is rejected by Nimbus's validation hooks.

Common situations: Resource server and authorization server key mismatch (wrong jwk-set-uri or realm); token signed with an algorithm excluded via setJwsAlgorithms (e.g. ES384 token on an RS256-only decoder); token tampered in transit; testing with a token from a dev issuer while configured for prod.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/6d9f238bc460f649. Report an issue: GitHub.

Appendix: source

Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java:302

	/**
	 * Use the given {@link Function} to validate JWTs.
	 * @param source the {@link Function}
	 * @return a {@link JwkSourceReactiveJwtDecoderBuilder} for further configurations
	 *
	 * @since 5.2
	 */
	public static JwkSourceReactiveJwtDecoderBuilder withJwkSource(Function<SignedJWT, Flux<JWK>> source) {
		return new JwkSourceReactiveJwtDecoderBuilder(source);
	}

	private static <C extends SecurityContext> JWTClaimsSet createClaimsSet(JWTProcessor<C> jwtProcessor,
			JWT parsedToken, @Nullable C context) {
		try {
			return jwtProcessor.process(parsedToken, context);
		}
		catch (BadJOSEException ex) {
			throw new BadJwtException("Failed to validate the token", ex);
		}
		catch (JOSEException ex) {
			throw new JwtException("Failed to validate the token", ex);
		}
	}

	/**
	 * A builder for creating {@link NimbusReactiveJwtDecoder} instances based on a
	 * <a target="_blank" href="https://tools.ietf.org/html/rfc7517#section-5">JWK Set</a>
	 * uri.
	 *
	 * @since 5.2
	 */
	public static final class JwkSetUriReactiveJwtDecoderBuilder {

		private static final JOSEObjectTypeVerifier<JWKSecurityContext> JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier<>(
				JOSEObjectType.JWT, null);

View on GitHub (pinned to 96852e8860)