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

  1. Verify cas.authn.mfa.webauthn relying-party id / server origin exactly match the URL and domain the browser uses
  2. Have the user re-register the authenticator (delete the stored credential registration) and retry
  3. Check that the request challenge issued by startAuthentication is the one being answered, not a cached page
  4. Confirm all CAS cluster nodes share the same WebAuthn configuration and credential registry
  5. 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

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


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)