apereo/cas · warning

Duo returned an Invalid response with message

Error message

Duo returned an Invalid response with message [{}] and detail [{}] when determining user account. This maybe a configuration error in the admin request and Duo will still be considered available.

What it means

BaseDuoSecurityAuthenticationService.getUserAccount calls the Duo Admin API for a user account. If the HTTP response code is above the error threshold it throws DuoSecurityException, but for 'invalid' (non-failing) codes it logs this warning and still considers Duo available. It usually means the admin request reached Duo but the response was not a clean success — often a misconfigured admin integration key or permission.

Solutions

  1. Verify the Duo Admin API integration key, secret key and hostname in cas.authn.mfa.duo properties
  2. Confirm the admin integration has the required permissions (read user info) in the Duo admin console
  3. Check whether the target username actually exists in the Duo directory
  4. Enable CAS debug logging for org.apereo.cas.adaptors.duo to see the full response payload

Example fix

// before
cas.authn.mfa.duo[0].admin-integration-key=wrong-ik
// after
cas.authn.mfa.duo[0].admin-integration-key=DI...
cas.authn.mfa.duo[0].admin-secret-key=...
cas.authn.mfa.duo[0].api-host=api-xxxx.duosecurity.com
Defensive patterns

Strategy: validation

Validate before calling

// before deploy: verify Duo admin credentials
// curl -H "Authorization: Basic $B64(IK:SK)" https://api-xxx.duosecurity.com/admin/v1/users/$user
typeGuard = null

Try / catch

try { duoService.getUserAccount(username); } catch (DuoSecurityException e) { LOGGER.warn("Duo admin request rejected: {}", e.getMessage()); /* treat duo as unavailable */ }

Prevention

When it happens

Trigger: Duo Admin API responds with a non-success (but not fatal) status code along with a message/detail when querying a username, e.g. user not found in Duo directory or insufficient admin integration rights.

Common situations: Wrong or under-privileged Duo Admin API credentials, user absent from Duo, or Duo account configuration changes; developers see 'Duo returned an Invalid response...' in logs while the MFA flow still proceeds with UNAVAILABLE/other status.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-duo-core/src/main/java/org/apereo/cas/adaptors/duo/authn/BaseDuoSecurityAuthenticationService.java:117

                val response = result.get(RESULT_KEY_RESPONSE);
                val authResult = response.get(RESULT_KEY_RESULT).asString().toUpperCase(Locale.ENGLISH);

                val status = DuoSecurityUserAccountStatus.valueOf(authResult);
                account.setProviderId(properties.getId());
                account.setStatus(status);
                account.setMessage(response.get(RESULT_KEY_STATUS_MESSAGE).asString());
                if (status == DuoSecurityUserAccountStatus.ENROLL) {
                    val enrollUrl = response.get(RESULT_KEY_ENROLL_PORTAL_URL).asString();
                    account.setEnrollPortalUrl(enrollUrl);
                }
            } else {
                val code = result.get(RESULT_KEY_CODE).asInt();
                if (code > RESULT_CODE_ERROR_THRESHOLD) {
                    LOGGER.warn("Duo returned a failure response with code: [{}]. Duo will be considered unavailable",
                        result.get(RESULT_KEY_MESSAGE));
                    throw new DuoSecurityException("Duo returned code %s: %s".formatted(code, result.get(RESULT_KEY_MESSAGE)));
                }
                LOGGER.warn("Duo returned an Invalid response with message [{}] and detail [{}] "
                        + "when determining user account. This maybe a configuration error in the admin request and Duo will "
                        + "still be considered available.",
                    result.hasNonNull(RESULT_KEY_MESSAGE) ? result.get(RESULT_KEY_MESSAGE).asString() : StringUtils.EMPTY,
                    result.hasNonNull(RESULT_KEY_MESSAGE_DETAIL) ? result.get(RESULT_KEY_MESSAGE_DETAIL).asString() : StringUtils.EMPTY);
            }
        } catch (final Exception e) {
            LOGGER.warn("Reaching Duo has failed with error: [{}]", e.getMessage(), e);
            account.setStatus(DuoSecurityUserAccountStatus.UNAVAILABLE);
        }

        userAccountCachedMap.put(account.getUsername(), account);
        LOGGER.debug("Fetched and cached duo user account [{}]", account);
        return account;
    }

    @Override
    public Optional<DuoSecurityAdminApiService> getAdminApiService() {
        if (StringUtils.isNotBlank(properties.getDuoAdminIntegrationKey()) && StringUtils.isNotBlank(properties.getDuoAdminSecretKey())) {

View on GitHub (pinned to e7288fc434)