spring-projects/spring-security · error · BadCredentialsException
Invalid basic authentication token
Error message
Invalid basic authentication token
What it means
After Base64-decoding the Basic auth payload, convert expects 'username:password' — the colon delimiter is mandatory per RFC 7617. If the decoded string contains no ':', BadCredentialsException('Invalid basic authentication token') is thrown because the credentials are structurally invalid.
Solutions
- Encode credentials as Base64(username + ":" + password) per RFC 7617
- Verify the client library's basic-auth helper is used instead of manual encoding
- Check header integrity through proxies (no truncation/re-encoding)
- Log the decoded shape (never the credentials) to confirm the missing delimiter
Example fix
// before String encoded = Base64.getEncoder().encodeToString(user.getBytes()); // missing ':' // after String encoded = Base64.getEncoder().encodeToString((user + ":" + password).getBytes(UTF_8));
Defensive patterns
Strategy: validation
Validate before calling
String decoded = new String(Base64.getDecoder().decode(base64Part), StandardCharsets.UTF_8);
if (!decoded.contains(":")) {
response.sendError(401, "Malformed basic auth payload; expected username:password");
return;
} Type guard
boolean isWellFormedBasicPayload(String decoded) {
return decoded != null && decoded.indexOf(':') >= 0;
} Try / catch
try {
Authentication a = converter.convert(request);
} catch (BadCredentialsException e) {
response.setHeader("WWW-Authenticate", "Basic realm=\"app\"");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
} Prevention
- Use a standard basic-auth helper instead of hand-rolled Base64 encoding
- Always include the ':' separator between username and password
- Use UTF-8 consistently when encoding credentials
- Unit-test credential encoding end-to-end against the server
When it happens
Trigger: convert decodes the Base64 portion of the Authorization header and token.indexOf(":") returns -1 — e.g. the Base64 value encodes only a username, or arbitrary garbage that decodes without a colon.
Common situations: Clients Base64-encoding the username only, or forgetting the ':' separator; corrupted/truncated Authorization headers; tests hard-coding incorrectly encoded values; non-UTF8 encoded payloads mangled in transit.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Empty basic authentication token
- Cookie token[1] did not contain a valid number (contained…
- DigestAuthenticationFilter.missingMandatory
- invalid_request
- invalid_request
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/088e322131fdf578.
Report an issue: GitHub.
Appendix: source
Thrown at web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationConverter.java:96
@Override
public @Nullable UsernamePasswordAuthenticationToken convert(HttpServletRequest request) {
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header == null) {
return null;
}
header = header.trim();
if (!StringUtils.startsWithIgnoreCase(header, AUTHENTICATION_SCHEME_BASIC)) {
return null;
}
if (header.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
throw new BadCredentialsException("Empty basic authentication token");
}
byte[] base64Token = header.substring(6).getBytes(StandardCharsets.UTF_8);
byte[] decoded = decode(base64Token);
String token = new String(decoded, getCredentialsCharset(request));
int delim = token.indexOf(":");
if (delim == -1) {
throw new BadCredentialsException("Invalid basic authentication token");
}
UsernamePasswordAuthenticationToken result = UsernamePasswordAuthenticationToken
.unauthenticated(token.substring(0, delim), token.substring(delim + 1));
result.setDetails(this.authenticationDetailsSource.buildDetails(request));
return result;
}
private byte[] decode(byte[] base64Token) {
try {
return Base64.getDecoder().decode(base64Token);
}
catch (IllegalArgumentException ex) {
throw new BadCredentialsException("Failed to decode basic authentication token");
}
}
protected Charset getCredentialsCharset(HttpServletRequest request) {
return getCredentialsCharset();View on GitHub (pinned to 96852e8860)