spring-projects/spring-security · error · BadCredentialsException
CasAuthenticationProvider.noServiceTicket
CasAuthenticationProvider.noServiceTicket
Error message
Failed to provide a CAS service ticket to validate
What it means
When authenticating a CasServiceTicketAuthenticationToken / UsernamePasswordAuthenticationToken, CasAuthenticationProvider requires non-empty credentials containing the CAS service ticket. If credentials are null or an empty string, it immediately throws BadCredentialsException — there is no ticket to hand to the TicketValidator, so CAS validation cannot proceed.
Source
Thrown at cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationProvider.java:118
}
@Override
public @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
// If an existing CasAuthenticationToken, just check we created it
if (authentication instanceof CasAuthenticationToken) {
if (this.key.hashCode() != ((CasAuthenticationToken) authentication).getKeyHash()) {
throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProvider.incorrectKey",
"The presented CasAuthenticationToken does not contain the expected key"));
}
return authentication;
}
// Ensure credentials are presented
if ((authentication.getCredentials() == null) || "".equals(authentication.getCredentials())) {
throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProvider.noServiceTicket",
"Failed to provide a CAS service ticket to validate"));
}
boolean stateless = (authentication instanceof CasServiceTicketAuthenticationToken token
&& token.isStateless());
CasAuthenticationToken result = null;
if (stateless) {
// Try to obtain from cache
result = this.statelessTicketCache.getByTicketId(authentication.getCredentials().toString());
}
if (result == null) {
result = this.authenticateNow(authentication);
result.setDetails(authentication.getDetails());
}
if (stateless) {
// Add to cache
this.statelessTicketCache.putTicketInCache(result);View on GitHub (pinned to 96852e8860)
Solutions
- Verify the CAS service/callback URL matches the service registered with the CAS server so the ticket query parameter is preserved.
- Check that CasAuthenticationFilter is handling the callback (filterProcessesUrl) and receiving the ticket parameter.
- Redirect the user to the CAS login page to obtain a new ticket when none is present.
- If constructing tokens programmatically, set credentials to the actual service ticket string.
- Catch BadCredentialsException and restart the CAS authentication flow.
Example fix
// before
Authentication auth = new UsernamePasswordAuthenticationToken(principal, "");
provider.authenticate(auth); // throws
// after
String ticket = request.getParameter("ticket");
if (ticket != null && !ticket.isEmpty()) {
Authentication auth = new CasServiceTicketAuthenticationToken(ticket, true);
provider.authenticate(auth);
} else {
response.sendRedirect(casLoginUrl); // obtain a new ticket
} Defensive patterns
Strategy: validation
Validate before calling
Object creds = authentication.getCredentials();
if (creds == null || "".equals(creds)) {
response.sendRedirect(casProperties.getLoginUrl()); // obtain a ticket first
return;
} Type guard
boolean hasServiceTicket(Authentication a) {
Object c = a.getCredentials();
return c instanceof String s && !s.isBlank();
} Try / catch
try {
return casAuthenticationProvider.authenticate(authentication);
} catch (BadCredentialsException e) {
// no ticket present: redirect to CAS login
return redirectService.initiateCasLogin();
} Prevention
- Register the exact callback service URL with the CAS server so ?ticket= is delivered
- Don't strip query parameters in proxies/gateways in front of the callback
- Handle bookmarked callback URLs by redirecting to CAS login
- In gateway/proxy (deferred) mode, expect empty tickets and fall back to redirect
When it happens
Trigger: authenticate() called with a token whose getCredentials() returns null or "" — e.g. POST to the CAS callback / j_spring_cas_security_check without a ticket parameter, a CAS server redirect lacking ?ticket=..., or code constructing an Authentication token manually without credentials.
Common situations: User bookmarking/reloading the callback URL (ticket already consumed and stripped); CAS server configured with a different service URL so the ticket parameter is dropped; proxy/gateway stripping query parameters; custom filter creating an empty token; CAS gateway mode where no ticket is issued.
Related errors
- CasAuthenticationProvider.incorrectKey
- Authentication.getCredentials() cannot be null
- RunAsImplAuthenticationProvider.incorrectKey
- <ticket validation failure message>
- Bad credentials
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/d0e97ba627695e10.
Report an issue: GitHub.