{"record":{"id":"f96920a8c5474ebe","repo":"apereo/cas","slug":"unable-to-accept-the-id-token-with-an-invalid-sub","errorCode":null,"errorMessage":"Unable to accept the ID token with an invalid [sub] claim","messagePattern":"Unable to accept the ID token with an invalid \\[sub\\] claim","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-aws-cognito-authentication/src/main/java/org/apereo/cas/authentication/AmazonCognitoAuthenticationAuthenticationHandler.java","lineNumber":72,"sourceCode":"        try {\n            val authParams = new HashMap<String, String>();\n            authParams.put(\"USERNAME\", credential.getUsername());\n            authParams.put(\"PASSWORD\", credential.toPassword());\n            val authRequest = AdminInitiateAuthRequest.builder();\n\n            val request = authRequest.authFlow(AuthFlowType.ADMIN_NO_SRP_AUTH)\n                .clientId(properties.getClientId())\n                .userPoolId(properties.getUserPoolId())\n                .authParameters(authParams).build();\n            val result = cognitoIdentityProvider.adminInitiateAuth(request);\n\n            if (\"NEW_PASSWORD_REQUIRED\".equalsIgnoreCase(result.challengeNameAsString())) {\n                throw new CredentialExpiredException();\n            }\n            val authenticationResult = result.authenticationResult();\n            val claims = jwtProcessor.process(authenticationResult.idToken(), new SimpleSecurityContext());\n            if (StringUtils.isBlank(claims.getSubject())) {\n                throw new FailedLoginException(\"Unable to accept the ID token with an invalid [sub] claim\");\n            }\n\n            val userResult = cognitoIdentityProvider.adminGetUser(AdminGetUserRequest.builder()\n                .userPoolId(properties.getUserPoolId())\n                .username(credential.getUsername()).build());\n\n            val attributes = new LinkedHashMap<String, List<Object>>();\n            attributes.put(\"userStatus\", CollectionUtils.wrap(userResult.userStatusAsString()));\n            attributes.put(\"userCreatedDate\", CollectionUtils.wrap(userResult.userCreateDate().toEpochMilli()));\n            attributes.put(\"userModifiedDate\", CollectionUtils.wrap(userResult.userLastModifiedDate().toEpochMilli()));\n\n            val userAttributes = userResult.userAttributes();\n            userAttributes.forEach(attr -> {\n                if (!properties.getMappedAttributes().isEmpty() && properties.getMappedAttributes().containsKey(attr.name())) {\n                    val newName = properties.getMappedAttributes().get(attr.name());\n                    attributes.put(newName, CollectionUtils.wrap(attr.value()));\n                } else {\n                    attributes.put(attr.name(), CollectionUtils.wrap(attr.value()));","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-aws-cognito-authentication/src/main/java/org/apereo/cas/authentication/AmazonCognitoAuthenticationAuthenticationHandler.java#L54-L90","documentation":"Thrown by AmazonCognitoAuthenticationAuthenticationHandler.authenticateUsernamePasswordInternal after it verifies credentials against AWS Cognito and processes the returned ID token with a JWT processor. If the ID token's 'sub' claim is missing or blank, the handler cannot establish a subject for the principal and raises FailedLoginException. In practice this means Cognito authenticated the user but returned a token payload CAS cannot use.","triggerScenarios":"result.authenticationResult() yields an idToken whose decoded claims have no 'sub' — e.g. an unexpected/malformed ID token, a token issued by a misconfigured user pool, or jwtProcessor.process() decoding a token payload that lacks the subject claim.","commonSituations":"User pool misconfiguration (custom authentication flows, token customization via pre-token-generation Lambda stripping claims); pointing CAS at the wrong pool/region so tokens are odd; clocks/JWKS issues causing the processor to read a stale or unexpected token; NEW_PASSWORD_REQUIRED-style flows partially completed.","solutions":["Verify the Cognito user pool configuration (region, pool id, client id) in cas.authn.amazon-cognito[0] matches the pool actually issuing the tokens.","Inspect the ID token (decode its JWT payload) to confirm a 'sub' claim is present; if a pre-token-generation Lambda customizes claims, ensure it does not remove 'sub'.","Confirm the JWKS endpoint / signing key configuration so jwtProcessor processes the token with the correct keys rather than mis-decoding it.","Check that the user completed the full authentication challenge (e.g. NEW_PASSWORD_REQUIRED) so Cognito returns a normal AuthenticationResult with a valid ID token."],"exampleFix":"// before: no pre-token lambda check; ID token missing sub\nAdminGetUserRequest.builder().userPoolId(properties.getUserPoolId())...\n\n// after: validate pool settings so ID tokens carry 'sub'\n// aws cognito-idp describe-user-pool --user-pool-id <poolId>  (check lambda config)\n// ensure pre-token-generation trigger does not strip 'sub'","handlingStrategy":"validation","validationCode":"val claims = jwtProcessor.process(authenticationResult.idToken(), new SimpleSecurityContext());\nif (claims == null || StringUtils.isBlank(claims.getSubject())) {\n    throw new FailedLoginException(\"ID token has no 'sub' claim; check user pool / pre-token-generation config\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    authenticateAgainstCognito(credential);\n} catch (FailedLoginException e) {\n    LOGGER.warn(\"Cognito login failed: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Decode a sample ID token (jwt.io) to confirm 'sub' is present in your pool's tokens.","Review any pre-token-generation Lambda so it never removes required standard claims.","Keep user pool, client, region, and JWKS settings in sync with the pool actually issuing tokens."],"tags":["aws","cognito","jwt","oidc-token","authentication"],"backgroundTag":"invalid-json-response","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"}