spring-projects/spring-security · error · InvalidBearerTokenException

invalid_token

invalid_token

Error message

Invalid token

What it means

JwtAuthenticationProvider.getJwt() decodes the bearer token; when the decoder throws BadJwtException (structurally invalid JWT: bad signature format, unsupported alg, malformed claims), it is translated to InvalidBearerTokenException with message 'Invalid token' (or the BadJwtException's message), producing an OAuth2 invalid_token response. Other JwtExceptions (server-side issues like key fetch failures) become AuthenticationServiceException instead.

Source

Thrown at oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.java:104

	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		BearerTokenAuthenticationToken bearer = (BearerTokenAuthenticationToken) authentication;
		Jwt jwt = getJwt(bearer);
		AbstractAuthenticationToken token = this.jwtAuthenticationConverter.convert(jwt);
		Assert.notNull(token, "token cannot be null");
		if (token.getDetails() == null) {
			token.setDetails(bearer.getDetails());
		}
		this.logger.debug("Authenticated token");
		return token;
	}

	private Jwt getJwt(BearerTokenAuthenticationToken bearer) {
		try {
			return this.jwtDecoder.decode(bearer.getToken());
		}
		catch (BadJwtException failed) {
			this.logger.debug("Failed to authenticate since the JWT was invalid");
			throw new InvalidBearerTokenException((failed.getMessage() != null) ? failed.getMessage() : "Invalid token",
					failed);
		}
		catch (JwtException failed) {
			throw new AuthenticationServiceException(
					(failed.getMessage() != null) ? failed.getMessage() : "Invalid token", failed);
		}
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return BearerTokenAuthenticationToken.class.isAssignableFrom(authentication);
	}

	public void setJwtAuthenticationConverter(
			Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter) {
		Assert.notNull(jwtAuthenticationConverter, "jwtAuthenticationConverter cannot be null");
		this.jwtAuthenticationConverter = jwtAuthenticationConverter;
	}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Inspect the debug log line 'Failed to authenticate since the JWT was invalid' and the nested BadJwtException message for the root cause
  2. Have the client obtain a fresh token from the Authorization Server
  3. Decode the token at jwt.io to check header/payload structure
  4. Verify the resource server decoder config (jwkSetUri reachable, algorithms) matches the issuer
Defensive patterns

Strategy: try-catch

Validate before calling

// check token has 3 segments and is not visibly expired before calling
if (jwt.split("\\.").length != 3) throw new IllegalStateException("Malformed JWT");

Try / catch

try {
    Jwt jwt = decoder.decode(token);
} catch (InvalidBearerTokenException e) {
    // token structurally invalid — do not retry, re-authenticate
    throw new UnauthorizedException("Token rejected", e);
} catch (AuthenticationServiceException e) {
    // server-side issue (e.g. JWKS fetch failed) — safe to retry
}

Prevention

When it happens

Trigger: Bearer token fails JwtDecoder.decode() with BadJwtException — malformed token, unsupported algorithm, expired/malformed claims depending on decoder — during JwtAuthenticationProvider.authenticate().

Common situations: Client sending a truncated or hand-edited JWT; expired token surfaced as 'Invalid token' by some decoders; issuer key rotation invalidating signatures; copy-paste errors losing part of the Authorization header value.

Understand the failure class

Related errors


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