spring-projects/spring-security · error · OAuth2AuthenticationException
invalid_token
invalid_token
Error message
Bearer token is malformed
What it means
The reactive (WebFlux) ServerBearerTokenAuthenticationConverter throws this when the Authorization header starts with 'Bearer ' but the remainder fails the token regex — typically whitespace or multiple values. It is the reactive counterpart of error 460 and maps to the invalid_token OAuth2 error before any token validation.
Source
Thrown at oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java:108
if (!StringUtils.hasText(accessToken)) {
BearerTokenError error = BearerTokenErrors
.invalidRequest("The requested token parameter is an empty string");
return Mono.error(new OAuth2AuthenticationException(error));
}
return Mono.just(accessToken);
}
private Mono<String> resolveFromAuthorizationHeader(HttpHeaders headers) {
String authorization = headers.getFirst(this.bearerTokenHeaderName);
if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
return Mono.empty();
}
Matcher matcher = authorizationPattern.matcher(authorization);
if (!matcher.matches()) {
BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed");
throw new OAuth2AuthenticationException(error);
}
return Mono.just(matcher.group("token"));
}
private Flux<String> resolveAccessTokenFromQueryString(ServerHttpRequest request) {
if (!this.allowUriQueryParameter || !HttpMethod.GET.equals(request.getMethod())) {
return Flux.empty();
}
return resolveTokens(request.getQueryParams());
}
private Flux<String> resolveAccessTokenFromBody(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest();
if (!this.allowFormEncodedBodyParameter
|| !MediaType.APPLICATION_FORM_URLENCODED.equals(request.getHeaders().getContentType())
|| !HttpMethod.POST.equals(request.getMethod())) {View on GitHub (pinned to 96852e8860)
Solutions
- Trim the token and rebuild the header so it is exactly 'Bearer <token>'
- Regenerate the token if it contains characters outside the RFC token charset
- Inspect the raw header at the edge (e.g. with a WebFilter) to find what is actually transmitted
- Use a custom ServerBearerTokenAuthenticationConverter if your tokens legitimately deviate from the default pattern
Example fix
// before webClient.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token); // after webClient.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token.trim());
Defensive patterns
Strategy: validation
Validate before calling
String auth = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (auth != null && auth.startsWith("Bearer ")) {
String token = auth.substring(7).trim();
if (token.isEmpty() || token.contains(" ")) {
return Mono.error(new IllegalArgumentException("Malformed bearer token"));
}
} Type guard
boolean isValidBearerHeader(String header) {
return header != null && header.matches("^Bearer [!-~]+$");
} Try / catch
try {
return chain.filter(exchange);
} catch (OAuth2AuthenticationException e) {
if ("invalid_token".equals(e.getError().getErrorCode())) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders().add("WWW-Authenticate", "Bearer error=\"invalid_token\"");
}
return Mono.error(e);
} Prevention
- Normalize tokens (trim) at client construction time, once
- Add a WebFilter-level test that asserts a well-formed Authorization header
- Avoid string concatenation for headers; use header-builder APIs
- Watch for reactive clients adding headers per-request alongside defaults
When it happens
Trigger: A WebFlux application receives 'Authorization: Bearer <value>' where <value> contains spaces, a newline, or multiple space-separated tokens, so authorizationPattern.matcher(authorization).matches() fails inside resolveFromAuthorizationHeader.
Common situations: Tokens copied with trailing whitespace from terminals or logs; clients URL-encoding or wrapping tokens; gateway header rewriting inserting spaces; empty bearer values ('Bearer ' with nothing after).
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- invalid_id_token
- OAuth2Error read from WWW-Authenticate header or error respo
- missing_user_info_uri
- missing_user_name_attribute
- invalid_user_info_response
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/b6b042be03f6ec41.
Report an issue: GitHub.