apereo/cas · warning · InvalidCibaRequestException

CIBA request is not ready to grant access tokens

Error message

CIBA request %s is not ready to grant access tokens

What it means

AccessTokenCibaGrantRequestExtractor.extractRequest throws InvalidCibaRequestException with this message when the stored CIBA request (looked up by auth_req_id) is not yet 'ready' — i.e. the backchannel authentication has not been completed/approved yet. The client is polling too early and must retry with backoff (per CIBA spec, authorization_pending).

Solutions

  1. Client should retry after the 'interval' from the backchannel auth response, treating this as authorization_pending
  2. Verify the end-user completed authentication in the CIBA authentication device flow
  3. In ping mode, wait for the client notification endpoint callback before polling the token endpoint
  4. Check that the stored CIBA request hasn't expired and the correct auth_req_id was sent

Example fix

// before: poll immediately without waiting
post(tokenEndpoint, authReqId) // throws while user pending
// after: honor interval and pending state
while (!granted) { sleep(interval); result = poll(authReqId); if (result.status==400 && result.error=="authorization_pending") continue; }
Defensive patterns

Strategy: retry

Validate before calling

var ciba = cibaStore.get(authReqId);
if (ciba == null) throw new InvalidGrantException("unknown auth_req_id");
if (!ciba.isReady()) throw new AuthorizationPendingException("CIBA request not yet approved");

Try / catch

try { return extractor.extractRequest(context); } catch (InvalidCibaRequestException e) { if (e.getMessage().contains("is not ready")) { respondAuthorizationPending(interval); return null; } throw e; }

Prevention

When it happens

Trigger: A CIBA token request carries an auth_req_id whose stored OidcCibaRequest fails cibaRequest.isReady(); e.g. the end user has not yet authenticated/consented in the authentication device flow.

Common situations: Client polls immediately after initiating backchannel auth without honoring interval; user hasn't completed login on their device; slow notification delivery in ping mode.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/ciba/AccessTokenCibaGrantRequestExtractor.java:75

        val audit = AuditableContext.builder()
            .service(service)
            .registeredService(registeredService)
            .authentication(cibaRequest.getAuthentication())
            .build();
        val accessResult = configurationContext.getRegisteredServiceAccessStrategyEnforcer().execute(audit);
        accessResult.throwExceptionIfNeeded();

        if (!registeredService.getSupportedGrantTypes().contains(getGrantType().getType())
            || StringUtils.isBlank(registeredService.getBackchannelClientNotificationEndpoint())
            || StringUtils.isBlank(registeredService.getBackchannelTokenDeliveryMode())) {
            throw new InvalidCibaRequestException("Registered OpenID Connect relying party does not support backchannel authentication requests");
        }
        val deliveryMode = OidcBackchannelTokenDeliveryModes.valueOf(registeredService.getBackchannelTokenDeliveryMode().toUpperCase(Locale.ENGLISH));
        if (deliveryMode != OidcBackchannelTokenDeliveryModes.POLL && deliveryMode != OidcBackchannelTokenDeliveryModes.PING) {
            throw new InvalidCibaRequestException("Backchannel token delivery mode cannot grant access tokens");
        }
        if (!cibaRequest.isReady()) {
            throw new InvalidCibaRequestException("CIBA request %s is not ready to grant access tokens".formatted(authRequestId));
        }
        
        return AccessTokenRequestContext.builder()
            .service(service)
            .authentication(cibaRequest.getAuthentication())
            .registeredService(registeredService)
            .responseType(getResponseType())
            .grantType(getGrantType())
            .scopes(cibaRequest.getScopes())
            .userProfile(profile)
            .clientId(registeredService.getClientId())
            .generateRefreshToken(registeredService.isGenerateRefreshToken())
            .build();

    }

    @Override
    public boolean supports(final WebContext context) {

View on GitHub (pinned to e7288fc434)