apereo/cas · error · FailedLoginException

Could not authenticate account for

Error message

Could not authenticate account for 

What it means

SyncopeAuthenticationHandler.authenticateUsernamePasswordInternal throws FailedLoginException when authenticateSyncopeUser returns an empty Optional, i.e. Syncope did not authenticate the supplied username/password (bad credentials, unknown user, or an upstream call that yielded no user). CAS translates that into a generic FailedLoginException for the standard authentication flow.

Solutions

  1. Verify the username/password are correct and the user is in the configured Syncope domain (cas.authn.syncope.domain)
  2. Check cas.authn.syncope.url, basic-authn-username/password used to call Syncope, and network reachability from CAS to Syncope
  3. Confirm the user's realm in Syncope is one the configured admin account may access
  4. Enable debug logging on Syncope side to see why the auth REST call returns empty
  5. If this persists without user error, inspect Syncope access tokens / core REST config

Example fix

// before
cas.authn.syncope.url=http://localhost:8080/syncope
cas.authn.syncope.domain=Two
// after
cas.authn.syncope.url=http://syncope:8080/syncope
cas.authn.syncope.domain=Two
cas.authn.syncope.basic-authn-username=admin
cas.authn.syncope.basic-authn-password=secret
Defensive patterns

Strategy: retry

Validate before calling

// before CAS login, check reachability
try (var resp = HttpClient.newHttpClient().send(
    HttpRequest.newBuilder(URI.create(syncopeUrl + "/rest/users?FIQLString=username==" + u)).header("Authorization", basic).build(),
    BodyHandlers.ofString())) {
    if (resp.statusCode() != 200) throw new IllegalStateException("Syncope unreachable: " + resp.statusCode());
}

Try / catch

try {
    return authenticationManager.authenticate(transaction);
} catch (FailedLoginException e) {
    LOGGER.warn("Syncope login failed for user", e);
    throw new BadCredentialsException("invalid.username.or.password");
} catch (Exception e) {
    // network / 5xx — consider retry or degraded mode
}

Prevention

When it happens

Trigger: POST to Syncope's REST authentication endpoint for the configured domain returns no user (401/404, wrong credentials, or non-matching realm) so authenticateSyncopeUser yields Optional.empty.

Common situations: Wrong password or username typo; user exists in a different Syncope domain/realm than cas.authn.syncope.domain; misconfigured syncopeRestUrl or admin credentials for the authentication REST call; Syncope access-token/admin user lacking rights in the target realm.

Understand the failure class

Related errors


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

Appendix: source

Thrown at support/cas-server-support-syncope-authentication/src/main/java/org/apereo/cas/syncope/SyncopeAuthenticationHandler.java:75

        val result = authenticateSyncopeUser(credential);
        if (result.isPresent()) {
            val user = result.get();
            LOGGER.debug("Received Syncope user object as [{}]", user);
            if (user.has("suspended") && user.get("suspended").asBoolean()) {
                throw new AccountDisabledException(
                    "Could not authenticate forbidden account for " + credential.getUsername());
            }
            if (user.has("mustChangePassword") && user.get("mustChangePassword").asBoolean()) {
                throw new AccountPasswordMustChangeException(
                    "Account password must change for " + credential.getUsername());
            }
            val principalAttributes = SyncopeUtils.convertFromUserEntity(user, properties.getAttributeMappings());
            val name = properties.getAttributeMappings().getOrDefault("domain", "syncopeDomain");
            principalAttributes.put(name, CollectionUtils.wrapList(syncopeDomain));
            val principal = principalFactory.createPrincipal(user.get("username").asString(), principalAttributes);
            return createHandlerResult(credential, principal, new ArrayList<>());
        }
        throw new FailedLoginException("Could not authenticate account for " + credential.getUsername());
    }

    protected Optional<JsonNode> authenticateSyncopeUser(final UsernamePasswordCredential credential) {
        HttpResponse response = null;
        try {
            val syncopeRestUrl = Strings.CI.appendIfMissing(
                SpringExpressionLanguageValueResolver.getInstance().resolve(properties.getUrl()),
                "/rest/users/self");
            val exec = HttpExecutionRequest.builder()
                .method(HttpMethod.GET)
                .url(syncopeRestUrl)
                .basicAuthUsername(credential.getUsername())
                .basicAuthPassword(credential.toPassword())
                .headers(CollectionUtils.wrap(SyncopeUtils.SYNCOPE_HEADER_DOMAIN, syncopeDomain))
                .maximumRetryAttempts(properties.getMaxRetryAttempts())
                .build();
            response = HttpUtils.execute(exec);
            if (response != null) {

View on GitHub (pinned to e7288fc434)