{"record":{"id":"fcd8feb92eee4ffe","repo":"apereo/cas","slug":"backchannel-token-delivery-mode-cannot-grant-acces","errorCode":null,"errorMessage":"Backchannel token delivery mode cannot grant access tokens","messagePattern":"Backchannel token delivery mode cannot grant access tokens","errorType":"exception","errorClass":"InvalidCibaRequestException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/ciba/AccessTokenCibaGrantRequestExtractor.java","lineNumber":72,"sourceCode":"        val decodedId = cibaFactory.decodeId(authRequestId);\n        val cibaRequest = configurationContext.getTicketRegistry().getTicket(decodedId, OidcCibaRequest.class);\n\n        val audit = AuditableContext.builder()\n            .service(service)\n            .registeredService(registeredService)\n            .authentication(cibaRequest.getAuthentication())\n            .build();\n        val accessResult = configurationContext.getRegisteredServiceAccessStrategyEnforcer().execute(audit);\n        accessResult.throwExceptionIfNeeded();\n\n        if (!registeredService.getSupportedGrantTypes().contains(getGrantType().getType())\n            || StringUtils.isBlank(registeredService.getBackchannelClientNotificationEndpoint())\n            || StringUtils.isBlank(registeredService.getBackchannelTokenDeliveryMode())) {\n            throw new InvalidCibaRequestException(\"Registered OpenID Connect relying party does not support backchannel authentication requests\");\n        }\n        val deliveryMode = OidcBackchannelTokenDeliveryModes.valueOf(registeredService.getBackchannelTokenDeliveryMode().toUpperCase(Locale.ENGLISH));\n        if (deliveryMode != OidcBackchannelTokenDeliveryModes.POLL && deliveryMode != OidcBackchannelTokenDeliveryModes.PING) {\n            throw new InvalidCibaRequestException(\"Backchannel token delivery mode cannot grant access tokens\");\n        }\n        if (!cibaRequest.isReady()) {\n            throw new InvalidCibaRequestException(\"CIBA request %s is not ready to grant access tokens\".formatted(authRequestId));\n        }\n        \n        return AccessTokenRequestContext.builder()\n            .service(service)\n            .authentication(cibaRequest.getAuthentication())\n            .registeredService(registeredService)\n            .responseType(getResponseType())\n            .grantType(getGrantType())\n            .scopes(cibaRequest.getScopes())\n            .userProfile(profile)\n            .clientId(registeredService.getClientId())\n            .generateRefreshToken(registeredService.isGenerateRefreshToken())\n            .build();\n\n    }","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/ciba/AccessTokenCibaGrantRequestExtractor.java#L54-L90","documentation":"AccessTokenCibaGrantRequestExtractor.extractRequest throws InvalidCibaRequestException with this message when the registered service's backchannelTokenDeliveryMode parses to something other than POLL or PING. Only those modes can complete a CIBA grant at the token endpoint, so CAS refuses the access-token grant.","triggerScenarios":"registeredService.getBackchannelTokenDeliveryMode() parses (case-insensitively) to a mode other than POLL or PING — e.g. PUSH or a typo — while servicing a CIBA token request.","commonSituations":"Admin configured delivery mode 'push'; typo like 'pol' would actually fail earlier at valueOf with IllegalArgumentException; client expects push but token endpoint only serves poll/ping grants.","solutions":["Set the service's backchannelTokenDeliveryMode to 'poll' or 'ping'","If PUSH delivery is required, implement/use the push notification path instead of polling the token endpoint","Note valueOf on an unknown mode string throws IllegalArgumentException before this check — ensure the value is a valid OidcBackchannelTokenDeliveryModes constant"],"exampleFix":"// before (service definition)\n\"backchannelTokenDeliveryMode\": \"push\"\n// after\n\"backchannelTokenDeliveryMode\": \"poll\"","handlingStrategy":"validation","validationCode":"var mode = service.getBackchannelTokenDeliveryMode();\nif (!\"poll\".equalsIgnoreCase(mode) && !\"ping\".equalsIgnoreCase(mode)) {\n    throw new IllegalStateException(\"CIBA token grant requires delivery mode poll|ping, got: \" + mode);\n}","typeGuard":null,"tryCatchPattern":"try { return extractor.extractRequest(context); } catch (InvalidCibaRequestException e) { if (e.getMessage().contains(\"delivery mode\")) { throw new InvalidGrantException(\"Unsupported CIBA delivery mode\"); } throw e; }","preventionTips":["Only use 'poll' or 'ping' as backchannelTokenDeliveryMode values","Use push mode only via the dedicated push delivery flow, not token-endpoint polling","Validate service definitions against the OidcBackchannelTokenDeliveryModes enum before saving"],"tags":["oidc","ciba","configuration","delivery-mode"],"backgroundTag":"invalid-enum-value","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}