apereo/cas · error · AssertionFailedException
Assertion failed
Error message
Assertion failed
What it means
WebAuthn authentication finished but the assertion could not be verified by the Yubico WebAuthn server. The server returns the failure as a list of error messages rather than throwing; 'Assertion failed: Invalid assertion.' is the generic mismatch path, AssertionFailedException is the library-detected path, and unexpected exceptions are reported as a likely bug.
Solutions
- Verify cas.authn.mfa.webauthn relying-party id / server origin exactly match the URL and domain the browser uses
- Have the user re-register the authenticator (delete the stored credential registration) and retry
- Check that the request challenge issued by startAuthentication is the one being answered, not a cached page
- Confirm all CAS cluster nodes share the same WebAuthn configuration and credential registry
- Enable DEBUG logging on com.yubico.core.WebAuthnServer to see the underlying AssertionFailedException detail
Example fix
// before: reusing a stale challenge page finishAuthentication(oldRequest) // after: fetch a fresh assertion request, then finish val req = webAuthnServer.startAuthentication(username) // ...browser completes req... webAuthnServer.finishAuthentication(newRequest)
Defensive patterns
Strategy: validation
Validate before calling
if (webAuthnCredentialRepository.findByUsername(username) == null) throw new IllegalStateException("User has no registered WebAuthn credential"); Try / catch
var result = webAuthnServer.finishAuthentication(request);
if (result.isLeft()) { /* show result.getLeft() to the user, offer re-registration */ } Prevention
- Keep RP id and origin identical across all CAS nodes and browser-facing URLs
- Always answer the challenge from the current authentication session
- Delete stale credential registrations after hardware token changes
When it happens
Trigger: finishAuthentication() is called with a request whose signature, challenge, origin, RP ID, user handle, or credential counter does not match the stored credential (AssertionFailedException), or whose assertion is structurally invalid (generic 'Invalid assertion' branch).
Common situations: Client authenticating with a credential registered to a different relying party ID or origin; replayed or stale challenge; authenticator counter regression (cloned token); user submitting an assertion for an unregistered credential; multiple CAS nodes with different RP IDs in config.
Related errors
- Authentication handler is disabled
- No user can be accepted because none is defined
- not found in backing map.
- Unable to authenticate
- No authentication handlers could be resolved to support the…
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/103ef47325c499d3.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-webauthn-core/src/main/java/com/yubico/core/WebAuthnServer.java:253
e
);
}
val session = sessionManager.createSession(request, assertionResult.getCredential().getUserHandle());
return Either.right(
new SuccessfulAuthenticationResult(
assertionRequestWrapper,
assertionResponse,
userStorage.getRegistrationsByUsername(assertionResult.getUsername()),
assertionResult.getUsername(),
session
)
);
} else {
return Either.left(List.of("Assertion failed: Invalid assertion."));
}
} catch (final AssertionFailedException e) {
LOGGER.warn("Assertion failed", e);
return Either.left(List.of("Assertion failed", e.getMessage()));
} catch (final Exception e) {
LOGGER.error("Assertion failed", e);
return Either.left(List.of("Assertion failed unexpectedly; this is likely a bug.", e.getMessage()));
}
}
}
@Value
public static class SuccessfulRegistrationResult {
boolean success;
RegistrationRequest request;
RegistrationResponse response;
CredentialRegistration registration;
View on GitHub (pinned to e7288fc434)