apereo/cas · warning
Security token linked to ticket
Error message
Security token linked to ticket [{}] has expired What it means
The security-token ticket was found and valid, but the SecurityToken object it carries is null or itself expired, so the controller cannot return a usable token and logs this warning before returning null.
Solutions
- Increase the STS-issued token lifetime to exceed the security-token ticket TTL
- Decrease the ticket TTL to match token lifetime so they expire together
- Force the user to restart the federation flow to get a fresh token
- Check registry serialization if tokens come back null on clustered deployments
Example fix
// before: token lifetime shorter than ticket TTL cas.authn.wsfed-idp.security-token-tickets.time-to-kill-in-seconds=600 // after: align TTLs cas.authn.wsfed-idp.security-token-tickets.time-to-kill-in-seconds=300
Defensive patterns
Strategy: retry
Try / catch
if (token == null) { /* redirect user to restart the sign-in flow for a fresh token */ } Prevention
- Align security-token and ticket TTLs so the ticket never outlives the token
- Keep token payload small and serializable in clustered registries
- Monitor STS issuance latency to avoid long pauses mid-flow
When it happens
Trigger: getSecurityTokenFromRequest(): stt.getSecurityToken() is null, or stt.getSecurityToken().isExpired() is true after successful ticket lookup.
Common situations: Token TTL shorter than the ticket TTL, so the ticket outlives its token; STS issued token with very short lifetime; deserialization issue in a clustered registry returning a token object that cannot be reconstructed (null); long-paused browser flow.
Related errors
- No security token could be retrieved for service
- Token has expired: and is after
- Token has expired
- No groovy script cache manager is available to execute…
- Unable to determine the [WA] parameter
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/6bd2740d6b337cd8.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-ws-idp/src/main/java/org/apereo/cas/ws/idp/web/BaseWSFederationRequestController.java:89
* @return the security token from request
*/
protected SecurityToken getSecurityTokenFromRequest(final HttpServletRequest request) {
val cookieValue = configContext.getTicketGrantingTicketCookieGenerator().retrieveCookieValue(request);
if (StringUtils.isNotBlank(cookieValue)) {
val tgt = configContext.getTicketRegistry().getTicket(cookieValue, TicketGrantingTicket.class);
if (tgt != null) {
val sts = tgt.getDescendantTickets().stream()
.filter(t -> t.startsWith(SecurityTokenTicket.PREFIX))
.findFirst()
.orElse(null);
if (StringUtils.isNotBlank(sts)) {
val stt = configContext.getTicketRegistry().getTicket(sts, SecurityTokenTicket.class);
if (stt == null || stt.isExpired()) {
LOGGER.warn("Security token ticket [{}] is not found or has expired", sts);
return null;
}
if (stt.getSecurityToken() == null || stt.getSecurityToken().isExpired()) {
LOGGER.warn("Security token linked to ticket [{}] has expired", sts);
return null;
}
return stt.getSecurityToken();
}
}
}
return null;
}
protected boolean shouldRenewAuthentication(final WSFederationRequest fedRequest,
final HttpServletRequest request) {
if (StringUtils.isBlank(fedRequest.wfresh()) || !NumberUtils.isCreatable(fedRequest.wfresh())) {
return false;
}
val ttl = Long.parseLong(fedRequest.wfresh().trim());
if (ttl == 0) {
return false;View on GitHub (pinned to e7288fc434)