{"record":{"id":"0c51fde3cd2b9d4e","repo":"apereo/cas","slug":"subject-token-type-s-is-not-supported-0c51fd","errorCode":null,"errorMessage":"Subject token type %s is not supported","messagePattern":"Subject token type (.+?) is not supported","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oauth-core-api/src/main/java/org/apereo/cas/support/oauth/web/response/accesstoken/ext/AccessTokenTokenExchangeGrantRequestExtractor.java","lineNumber":116,"sourceCode":"        val subjectToken = requestParameterResolver.resolveRequestParameter(webContext, OAuth20Constants.SUBJECT_TOKEN)\n            .orElseThrow(() -> new IllegalArgumentException(\"Subject token cannot be undefined\"));\n        return switch (subjectTokenType) {\n            case ACCESS_TOKEN -> {\n                val token = configurationContext.getTicketRegistry().getTicket(subjectToken, OAuth20AccessToken.class);\n                val registeredService = OAuth20Utils.getRegisteredOAuthServiceByClientId(configurationContext.getServicesManager(), token.getClientId());\n                yield new TokenExchangeRequest(token, token.getService(), registeredService, token.getAuthentication());\n            }\n            case JWT -> {\n                val claimSet = configurationContext.getAccessTokenJwtBuilder().unpack(Optional.empty(), subjectToken);\n                val service = configurationContext.getWebApplicationServiceServiceFactory().createService(claimSet.getIssuer());\n                service.getAttributes().put(OAuth20Constants.CLIENT_ID, List.of(claimSet.getIssuer()));\n                val registeredService = OAuth20Utils.getRegisteredOAuthServiceByClientId(configurationContext.getServicesManager(), claimSet.getIssuer());\n                val userProfile = extractUserProfile(webContext).orElseThrow();\n                val authentication = configurationContext.getAuthenticationBuilder()\n                    .build(userProfile, registeredService, webContext, service);\n                yield new TokenExchangeRequest(claimSet, service, registeredService, authentication);\n            }\n            default -> throw new IllegalArgumentException(\"Subject token type %s is not supported\".formatted(subjectTokenType));\n        };\n    }\n\n    protected Authentication getActorTokenAuthentication(final WebContext webContext, final TokenExchangeRequest extractedRequest) throws Throwable {\n        val configurationContext = getConfigurationContext().getObject();\n        val actorToken = configurationContext.getRequestParameterResolver().resolveRequestParameter(webContext, OAuth20Constants.ACTOR_TOKEN);\n        val actorTokenType = configurationContext.getRequestParameterResolver().resolveRequestParameter(webContext, OAuth20Constants.ACTOR_TOKEN_TYPE)\n            .map(OAuth20TokenExchangeTypes::from);\n        FunctionUtils.throwIf(actorToken.isPresent() && actorTokenType.isEmpty(),\n            () -> new IllegalArgumentException(\"Actor token type cannot be undefined when actor token is provided\"));\n        if (actorToken.isPresent()) {\n            val actorAuthentication = extractActorTokenAuthentication(webContext, extractedRequest);\n            val tokenExchangePolicy = extractedRequest.registeredService() != null ? extractedRequest.registeredService().getTokenExchangePolicy() : null;\n            if (tokenExchangePolicy == null || tokenExchangePolicy.canSubjectTokenActAs(extractedRequest.authentication(),\n                actorAuthentication, actorTokenType.map(OAuth20TokenExchangeTypes::getType).orElse(null))) {\n                return actorAuthentication;\n            }\n        }","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oauth-core-api/src/main/java/org/apereo/cas/support/oauth/web/response/accesstoken/ext/AccessTokenTokenExchangeGrantRequestExtractor.java#L98-L134","documentation":"CAS's OAuth token-exchange grant extractor only supports a fixed set of subject_token_type values (access token and JWT). When the switch on subjectTokenType falls through to default, it throws this IllegalArgumentException, aborting the RFC 8693 token exchange before any token is issued.","triggerScenarios":"POSTing a token-exchange grant (grant_type=urn:ietf:params:oauth:grant-type:token-exchange) with a subject_token_type value other than the supported ACCESS_TOKEN or JWT constants, e.g. 'id_token' or an arbitrary URI like urn:ietf:params:oauth:token-type:saml2.","commonSituations":"Clients implementing token exchange send a non-standard subject_token_type (SAML2, id_token, or a typo'd URN); service was configured expecting JWT but client sends opaque tokens; version drift where newer RFC token types are not yet supported by the CAS OAuth core module.","solutions":["Send subject_token_type=urn:ietf:params:oauth:token-type:access_token and supply an existing CAS OAuth access token as subject_token","Or send subject_token_type=urn:ietf:params:oauth:token-type:jwt with a signed JWT the CAS access-token JWT builder can unpack and validate","Check for typos/URI casing in subject_token_type — it must match the supported enum values exactly","If a new token type is genuinely needed, extend the switch in extractSubjectTokenExchangeRequest in a custom extractor subclass","Verify the token-exchange feature is configured on the registered service so the correct extractor handles the request"],"exampleFix":"// before\ncurl -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange -d subject_token_type=urn:ietf:params:oauth:token-type:id_token ...\n// after\ncurl -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange -d subject_token_type=urn:ietf:params:oauth:token-type:jwt -d subject_token=<signed JWT> ...","handlingStrategy":"validation","validationCode":"Set<String> supported = Set.of(\"urn:ietf:params:oauth:token-type:access_token\",\"urn:ietf:params:oauth:token-type:jwt\");\nif (!supported.contains(subjectTokenType)) throw new IllegalArgumentException(\"Unsupported subject_token_type: \" + subjectTokenType);","typeGuard":"boolean isSupportedSubjectTokenType(String t) { return t != null && Set.of(\"urn:ietf:params:oauth:token-type:access_token\",\"urn:ietf:params:oauth:token-type:jwt\").contains(t); }","tryCatchPattern":"try { exchange(...); } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of(\"error\",\"unsupported_token_type\")); }","preventionTips":["Use the RFC 8693 token-type URN constants verbatim","Pin client token-exchange payloads to tested subject_token_type values","Add a preflight check against supported types before calling the endpoint"],"tags":["oauth","token-exchange","unsupported-value","http-400"],"backgroundTag":"unsupported-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"}