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

  1. Encode credentials as Base64(username + ":" + password) per RFC 7617
  2. Verify the client library's basic-auth helper is used instead of manual encoding
  3. Check header integrity through proxies (no truncation/re-encoding)
  4. 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

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.

Related errors


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)