spring-projects/spring-security · error · BadCredentialsException
GSSContext name of the context initiator is null
Error message
GSSContext name of the context initiator is null
What it means
Inside the KerberosValidateAction.run() executed via Subject.doAs, after acceptSecContext processes the ticket, context.getSrcName() returned null, meaning GSS could not determine the initiator's identity. This BadCredentialsException indicates the ticket bytes were not a valid/complete GSS context token.
Source
Thrown at kerberos/kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/sun/SunJaasKerberosTicketValidator.java:263
*/
private final class KerberosValidateAction implements PrivilegedExceptionAction<KerberosTicketValidation> {
byte[] kerberosTicket;
private KerberosValidateAction(byte[] kerberosTicket) {
this.kerberosTicket = kerberosTicket;
}
@Override
public KerberosTicketValidation run() throws Exception {
byte[] responseToken = new byte[0];
GSSName gssName = null;
GSSContext context = GSSManager.getInstance().createContext((GSSCredential) null);
while (!context.isEstablished()) {
responseToken = context.acceptSecContext(this.kerberosTicket, 0, this.kerberosTicket.length);
gssName = context.getSrcName();
if (gssName == null) {
throw new BadCredentialsException("GSSContext name of the context initiator is null");
}
}
GSSCredential delegationCredential = null;
if (context.getCredDelegState()) {
delegationCredential = context.getDelegCred();
}
if (!SunJaasKerberosTicketValidator.this.holdOnToGSSContext) {
context.dispose();
}
if (gssName == null) {
throw new BadCredentialsException("GSSContext name of the context initiator is null");
}
String servicePrincipal = SunJaasKerberosTicketValidator.this.servicePrincipal;
if (servicePrincipal == null) {
throw new IllegalStateException("servicePrincipal must be set");
}View on GitHub (pinned to 96852e8860)
Solutions
- Verify the token is Base64-decoded and includes the full SPNEGO wrapper; log token length before validation.
- Handle the initial empty/first-leg SPNEGO challenge separately instead of passing an empty token to validateTicket.
- Check intermediate proxies/load balancers are not stripping or rewriting the Authorization header.
- Confirm the browser/client actually obtained a Kerberos (not NTLM) token; check client-side SPN/realm configuration.
- Enable sun.security.krb5.debug and JGSS debugging (-Dsun.security.jgss.debug=true) to see where token parsing fails.
Example fix
// before
byte[] ticket = authHeader.getBytes(); // "Negotiate YII..." as raw bytes
validator.validateTicket(ticket);
// after
if (!authHeader.startsWith("Negotiate ")) throw new BadCredentialsException("no kerberos token");
byte[] ticket = Base64.getDecoder().decode(authHeader.substring("Negotiate ".length()));
if (ticket.length == 0) throw new BadCredentialsException("empty token");
validator.validateTicket(ticket); Defensive patterns
Strategy: validation
Validate before calling
// reject non-kerberos or empty tokens before validation
String header = request.getHeader("Authorization");
if (header == null || !header.startsWith("Negotiate ")) throw new BadCredentialsException("not a kerberos token");
byte[] token = Base64.getDecoder().decode(header.substring(10));
if (token.length < 10) throw new BadCredentialsException("token too short"); Type guard
static boolean isPlausibleSpnegoToken(byte[] t) {
// SPNEGO AbstractSyntaxNotification tag or NTLMSSP signature check
if (t == null || t.length < 8) return false;
boolean ntlm = t.length > 7 && t[0]=='N' && t[1]=='T' && t[2]=='L' && t[3]=='M';
return !ntlm;
} Try / catch
try {
KerberosTicketValidation v = validator.validateTicket(token);
} catch (BadCredentialsException e) {
LOGGER.warn("unparseable GSS token (len={})", token.length);
response.setHeader("WWW-Authenticate", "Negotiate");
response.sendError(401);
} Prevention
- Never pass the raw Authorization header bytes; always decode Base64.
- Reject NTLMSSP tokens (NTLMSSP signature) before invoking GSS validation.
- Ensure proxies/load balancers preserve the Authorization header.
- Handle the empty first-leg SPNEGO challenge before validation.
When it happens
Trigger: The kerberosTicket byte array passed to acceptSecContext is malformed, empty, truncated, or not a valid SPNEGO/Kerberos AP-REQ token, so the context never establishes an initiator name; the loop then throws this exception.
Common situations: Sending the raw 'Authorization: Negotiate xxx' header value without Base64 decoding, headers stripped or modified by proxies/load balancers, browser sending NTLM instead of Kerberos tokens, or an empty token body on a first-leg SPNEGO handshake being treated as a ticket.
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
- Kerberos validation not successful
- Error running rest call
- ticketValidator must be set
- userDetailsService must be set
- Unauthenticated or no response token
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/65cc25baf4a747c4.
Report an issue: GitHub.