spring-projects/spring-security · error · BadCredentialsException
Kerberos authentication failed
Error message
Kerberos authentication failed
What it means
KerberosMultiTier.runAuthentication performs the GSS-API context establishment loop and wraps ANY exception occurring there (GSSException, IO problems, malformed tokens) in a BadCredentialsException with this message. It means the multi-tier Kerberos handshake failed.
Solutions
- Inspect the cause exception carried by the BadCredentialsException for the GSS-level reason.
- Verify the target service principal name matches the SPN registered in the KDC (setspn -L).
- Check clock skew (max 5 minutes) and that credentials/keytab are valid and not expired with klist/kinit.
- Confirm krb5.conf has the correct realm and KDC addresses.
- Ensure both peers use compatible mechanisms (Kerberos V5 Oid).
Example fix
// before multiTier.authenticate(token, "HTTP/wrong-spn.example.com"); // after multiTier.authenticate(token, "HTTP/service.example.com@EXAMPLE.COM");
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-checks before handshake
Files.exists(Path.of(keytab));
if (Math.abs(System.currentTimeMillis() - kdcTimeOffsetMs) > 300_000) LOG.warn("clock skew high"); Try / catch
try {
multiTier.establish(...);
} catch (BadCredentialsException e) {
Throwable root = e.getCause(); // GSSException with real reason
LOG.error("Kerberos handshake failed: {}", root == null ? null : root.getMessage(), root);
throw new AuthenticationServiceException("Kerberos handshake failed", root);
} Prevention
- Keep service principal names exact and registered in the KDC.
- Monitor clock skew and refresh keytabs/TGTs before expiry.
- Validate krb5.conf realm/KDC settings in CI-like environment checks.
When it happens
Trigger: runAuthentication catching any Exception while establishing the GSS security context: invalid/mismatched SPN (targetService), expired credentials/keytab, kerberos ticket rejection, or I/O failure exchanging tokens with the peer.
Common situations: Wrong targetServicePrincipalName (SPN not registered in KDC), clock skew between client and KDC, expired TGT, or krb5.conf pointing at the wrong realm/KDC.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Unable to instantiate Oid:
- credentials cannot be null
- doExecute returned null
- Error running rest call
- Failed to obtain DirContext
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/2bebdea4d362ad92.
Report an issue: GitHub.
Appendix: source
Thrown at kerberos/kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosMultiTier.java:117
securityContext.requestMutualAuth(false);
securityContext.requestReplayDet(false);
securityContext.requestSequenceDet(false);
boolean established = false;
byte[] outToken = new byte[0];
while (!established) {
byte[] inToken = new byte[0];
outToken = securityContext.initSecContext(inToken, 0, inToken.length);
established = securityContext.isEstablished();
}
jaasContext.addToken(targetService, outToken);
}
catch (Exception ex) {
throw new BadCredentialsException("Kerberos authentication failed", ex);
}
}
private static Oid createOid(String oid) {
try {
return new Oid(oid);
}
catch (GSSException ex) {
throw new IllegalStateException("Unable to instantiate Oid: ", ex);
}
}
private KerberosMultiTier() {
}
}
View on GitHub (pinned to 96852e8860)