apereo/cas · error · AuthenticationException

Unable to locate authentication object in the webflow…

Error message

Unable to locate authentication object in the webflow context

What it means

DefaultCasDelegatingWebflowEventResolver.resolveInternal requires an in-progress AuthenticationResultBuilder in the webflow context before granting a TGT. If WebUtils.getAuthenticationResultBuilder(context) returns null, no authentication result was staged in this flow request, so it throws IllegalArgumentException wrapping AuthenticationException, typically surfaced as HTTP 401 via buildEventFromException handling.

Solutions

  1. Ensure the request goes through the standard CAS login flow so the AuthenticationResultBuilder is placed into flow scope before event resolution
  2. If integrating programmatically, first call WebUtils.putAuthenticationResultBuilder(context, builder) with a populated builder
  3. Check that authentication session management is enabled and the authn session hasn't expired mid-flow
  4. Clear stale flow execution state and restart the login flow

Example fix

// before: calling resolver without a builder
val events = casWebflowEventResolver.resolve(context, credential, service);
// after
val builder = WebUtils.getAuthenticationResultBuilder(context);
if (builder == null) {
    builder = new DefaultAuthenticationResultBuilder(...); // or route through /login
}
WebUtils.putAuthenticationResultBuilder(context, builder);
val events = casWebflowEventResolver.resolve(context, credential, service);
Defensive patterns

Strategy: type-guard

Validate before calling

if (WebUtils.getAuthenticationResultBuilder(context) == null) {
    // redirect to /login instead of resolving events
}

Type guard

AuthenticationResultBuilder builder = WebUtils.getAuthenticationResultBuilder(context);
boolean canResolve = builder != null;

Try / catch

try {
    return resolver.resolve(context, credentials, service);
} catch (IllegalArgumentException | AuthenticationException e) {
    response.setStatus(HttpStatus.UNAUTHORIZED.value());
    return Collections.emptySet();
}

Prevention

When it happens

Trigger: Resolving the authentication event outside the normal login flow (e.g. a direct POST to the event resolver or a service-ticket/renew request) where WebUtils.getAuthenticationResultBuilder has never been populated; hitting the resolver mid-flow after context reset; calling resolveFrom before any credentials were submitted.

Common situations: Direct-deep-linking into a flow state; SSO/session expiry wiping the flow scope; custom webflow actions clearing request context; misconfigured flow transitions skipping the credential-submission step.

Understand the failure class

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/6f4f2b7cd7df4e14. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/resolver/impl/DefaultCasDelegatingWebflowEventResolver.java:98

            val registeredService = determineRegisteredServiceForEvent(context, service);
            LOGGER.trace("Attempting to resolve candidate authentication events for service [{}]", service);
            val resolvedEvents = resolveCandidateAuthenticationEvents(context, service, registeredService);
            if (resolvedEvents.isEmpty()) {
                LOGGER.trace("No candidate authentication events were resolved for service [{}]", service);
            } else {
                LOGGER.trace("Authentication events resolved for [{}] are [{}]. Selecting final event...", service, resolvedEvents);
                WebUtils.putResolvedEventsAsAttribute(context, resolvedEvents);
                val finalResolvedEvent = this.selectiveResolver.resolveSingle(context);
                LOGGER.debug("The final authentication event resolved for [{}] is [{}]", service, finalResolvedEvent);
                if (finalResolvedEvent != null) {
                    return CollectionUtils.wrapSet(finalResolvedEvent);
                }
            }

            val builder = WebUtils.getAuthenticationResultBuilder(context);
            if (builder == null) {
                val msg = "Unable to locate authentication object in the webflow context";
                throw new IllegalArgumentException(new AuthenticationException(msg));
            }
            return CollectionUtils.wrapSet(grantTicketGrantingTicketToAuthenticationResult(context, builder, service));
        } catch (final Throwable exception) {
            val event = buildEventFromException(exception, context, credentials, service);
            val response = WebUtils.getHttpServletResponseFromExternalWebflowContext(context);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            LOGGER.debug("Authentication request failed with [{}], resulting in event [{}]", response.getStatus(), event);
            return CollectionUtils.wrapSet(event);
        }
    }

    @Override
    public void addDelegate(final CasWebflowEventResolver resolver) {
        if (BeanSupplier.isNotProxy(resolver)) {
            orderedResolvers.add(resolver);
        }
    }

View on GitHub (pinned to e7288fc434)