apereo/cas · error

Access token request cannot be validated for grant type

Error message

Access token request cannot be validated for grant type [{}] and client id [{}] given the redirect URI [{}]

What it means

In validateInternal of the authorization-code token request validator, the request only validates when redirect_uri and code are present AND the redirect_uri passes checkCallbackValid for the registered client. If any of those checks fails (or no registered service was resolvable), the validator logs this message and returns false, so the token endpoint refuses the authorization_code grant. It is a server-side warning, not a client-facing error string.

Solutions

  1. Send the exact same redirect_uri in the token request that was used in the /authorize request, and include the code parameter.
  2. Verify the redirect_uri survives your proxy (configure X-Forwarded-* / correct scheme) so checkCallbackValid still matches.
  3. Confirm client Basic auth credentials map to the same registered service that owns the code (registeredService.equals(codeRegisteredService)).
  4. Enable CAS debug logging for org.apereo.cas.support.oauth to see which of redirectUri/code/callback checks failed.

Example fix

// before
POST /oauth2.0/token grant_type=authorization_code&code=ABC
// after
POST /oauth2.0/token grant_type=authorization_code&code=ABC&redirect_uri=https://app.example.com/cb
Defensive patterns

Strategy: validation

Validate before calling

if (!code || !redirectUri) {
  throw new Error('token exchange requires both code and redirect_uri');
}
if (redirectUri !== authorizeRedirectUri) {
  throw new Error('redirect_uri must match the one used in /authorize');
}

Try / catch

try {
  const token = await exchangeCodeForToken({ code, redirectUri });
} catch (e) {
  if (/invalid_grant|cannot be validated/.test(e.message)) {
    // re-check redirect_uri parity and code expiry, then restart the flow
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /oauth2.0/token?grant_type=authorization_code where redirect_uri is missing, the code parameter is missing, or redirect_uri does not match the callback registered for the client_id found in the authenticated profile.

Common situations: Client omits redirect_uri on the token exchange though it was sent on /authorize (required for parity); redirect_uri rewritten by a proxy/load balancer (scheme or host changed); code parameter lost due to form-encoding issues in the token POST; client_id attribute missing from the basic-auth profile so the wrong service resolves.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-oauth-core-api/src/main/java/org/apereo/cas/support/oauth/validator/token/OAuth20AuthorizationCodeGrantTypeTokenRequestValidator.java:112

                .authentication(oauthCode.getAuthentication())
                .principal(accessStrategyPrincipal)
                .build();
            val accessResult = configurationContext.getRegisteredServiceAccessStrategyEnforcer().execute(audit);
            accessResult.throwExceptionIfNeeded();

            if (!registeredService.equals(codeRegisteredService)) {
                LOGGER.warn("OAuth code [{}] issued to service [{}] does not match [{}] provided, given the redirect URI [{}]",
                    code, serviceId, registeredService.getName(), redirectUri);
                return false;
            }

            if (!isGrantTypeSupportedBy(registeredService, grantType)) {
                LOGGER.warn("Requested grant type [{}] is not authorized by service definition [{}]", grantType, registeredService.getServiceId());
                return false;
            }
            return true;
        }
        LOGGER.warn("Access token request cannot be validated for grant type [{}] and client id [{}] given the redirect URI [{}]", grantType, clientId, redirectUri);
        return false;
    }
}

View on GitHub (pinned to e7288fc434)