apereo/cas · warning · InvalidCookieException
Invalid cookie Required remote address does not match
Error message
Invalid cookie %s Required remote address %s does not match %s
What it means
CAS binds cookies to the client's IP or geolocated location when created. On validation, if geoLocateClientSession is enabled and the stored location does not match the current resolved location, the cookie is rejected with InvalidCookieException. This prevents cookie theft/replay from a different client.
Solutions
- Disable geolocation session binding (set the relevant cookie geolocation property to false) if clients frequently change IPs
- Ensure the same geo-IP database version/config is deployed to every CAS node
- Investigate proxy/CDN headers (X-Forwarded-For) handling so client IP resolution is stable
- If IP changes are legitimate, use allowedIpAddressesPattern to whitelist the client's range instead of exact matching
Example fix
// before // cas.tgc.pinnable-session-cookie.geo-locate-client-session=true // after // cas.tgc.pinnable-session-cookie.geo-locate-client-session=false
Defensive patterns
Strategy: validation
Validate before calling
String storedIp = /* part 2 of compound cookie */;
String currentIp = ClientInfoHolder.getClientInfo().getClientIpAddress();
if (!storedIp.equals(currentIp)) { /* expect rejection unless allowedIpAddressesPattern covers it */ } Type guard
boolean ipBindingIntact(RegisteredServiceCookieProperties p, String stored, String current) {
return stored.equals(current) || RegexUtils.find(p.getAllowedIpAddressesPattern(), current);
} Try / catch
try { obtainCookieValue(...); } catch (InvalidCookieException e) {
LOGGER.warn("Cookie IP binding failed; forcing fresh login");
} Prevention
- Disable geo-location binding for mobile/VPN populations
- Deploy identical geo-IP databases cluster-wide
- Configure allowedIpAddressesPattern for NAT/proxy ranges
- Normalize X-Forwarded-For handling
When it happens
Trigger: cas.tgc GeoLocateClientSession enabled (or cookieProperties.isGeoLocateClientSession() true) and getClientGeoLocation(clientInfo) resolves a different location/IP than the one embedded in the cookie — client IP changed (mobile network, VPN, NAT pools), geo-IP database returns different results across nodes, or cookie replayed from another machine.
Common situations: User on roaming/mobile connection whose IP changed between requests; MaxMind/geoIP database versions differ across cluster nodes so the same IP geolocates differently; corporate proxy rotates egress IPs; developer tests across localhost vs actual IP.
Related errors
- Invalid cookie . Required remote address does not match
- Invalid cookie . Required user-agent does not match
- Invalid cookie . Required fields are empty
- Unable to match required remote address
- Invalid cookie . Required user-agent does not match
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/a21011f675ab55c9.
Report an issue: GitHub.
Appendix: source
Thrown at core/cas-server-core-cookie-api/src/main/java/org/apereo/cas/web/support/mgmr/DefaultCasCookieValueManager.java:127
if (Stream.of(cookieValue, cookieClientLocationOrIp, cookieUserAgent).anyMatch(StringUtils::isBlank)) {
throw new InvalidCookieException("Invalid cookie %s. Required fields are empty".formatted(cookieProperties.getName()));
}
val clientInfo = ClientInfoHolder.getClientInfo();
if (clientInfo == null) {
val message = "Unable to match required remote address %s because client ip at time of cookie creation is unknown for cookie %s"
.formatted(cookieProperties.getName(), cookieClientLocationOrIp);
LOGGER.warn(message);
throw new InvalidCookieException(message);
}
if (cookieProperties.isGeoLocateClientSession()) {
val clientLocationOrIp = getClientGeoLocation(clientInfo);
if (!cookieClientLocationOrIp.equals(clientLocationOrIp)) {
val message = "Invalid cookie %s Required remote address %s does not match %s"
.formatted(cookieProperties.getName(), cookieClientLocationOrIp, clientLocationOrIp);
LOGGER.warn(message);
throw new InvalidCookieException(message);
}
} else {
val clientIpAddress = clientInfo.getClientIpAddress();
if (!cookieClientLocationOrIp.equals(clientIpAddress)) {
if (StringUtils.isBlank(cookieProperties.getAllowedIpAddressesPattern())
|| !RegexUtils.find(cookieProperties.getAllowedIpAddressesPattern(), clientIpAddress)) {
val message = "Invalid cookie %s. Required remote address %s does not match %s"
.formatted(cookieProperties.getName(), cookieClientLocationOrIp, clientIpAddress);
LOGGER.warn(message);
throw new InvalidCookieException(message);
}
LOGGER.debug("Required remote address [{}] does not match [{}], but it's authorized to proceed",
cookieClientLocationOrIp, clientIpAddress);
}
}
val agent = HttpRequestUtils.getHttpServletRequestUserAgent(request);View on GitHub (pinned to e7288fc434)