{"record":{"id":"9dfe071a5a56e738","repo":"apereo/cas","slug":"invalid-credentials","errorCode":null,"errorMessage":"Invalid credentials: ","messagePattern":"Invalid credentials: ","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-azuread-authentication/src/main/java/org/apereo/cas/azure/ad/authentication/AzureActiveDirectoryAuthenticationHandler.java","lineNumber":126,"sourceCode":"            LOGGER.trace(\"Fetching token for [{}]\", username);\n            val result = getAccessTokenFromUserCredentials(username, credential.toPassword());\n            LOGGER.debug(\"Retrieved token [{}] for [{}]\", result.accessToken(), username);\n            val userInfo = getUserInfoFromGraph(result, username);\n            LOGGER.trace(\"Retrieved user info [{}]\", userInfo);\n            val userInfoMap = (Map<String, ?>) MAPPER.readValue(JsonValue.readHjson(userInfo).toString(), Map.class);\n            val attributeMap = new HashMap<String, List<Object>>(userInfoMap.size());\n            userInfoMap.forEach((key, value) -> {\n                val values = CollectionUtils.toCollection(value, ArrayList.class);\n                if (!values.isEmpty()) {\n                    attributeMap.put(key, values);\n                }\n            });\n            val principal = principalFactory.createPrincipal(username, attributeMap);\n            LOGGER.debug(\"Created principal for id [{}] and [{}] attributes\", username, attributeMap);\n            return createHandlerResult(credential, principal, new ArrayList<>());\n        } catch (final Exception e) {\n            LoggingUtils.error(LOGGER, e);\n            throw new FailedLoginException(\"Invalid credentials: \" + e.getMessage());\n        }\n    }\n}\n","sourceCodeStart":108,"sourceCodeEnd":130,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-azuread-authentication/src/main/java/org/apereo/cas/azure/ad/authentication/AzureActiveDirectoryAuthenticationHandler.java#L108-L130","documentation":"Catch-all in AzureActiveDirectoryAuthenticationHandler.authenticateUsernamePasswordInternal: any exception during the Azure AD username/password flow (token acquisition via getAccessTokenFromUserCredentials, Graph user-info fetch, or principal attribute mapping) is logged and rethrown as FailedLoginException(\"Invalid credentials: \" + e.getMessage()). The original exception's message is preserved but its type is flattened to a failed login.","triggerScenarios":"Any Exception thrown inside authenticateUsernamePasswordInternal — MSAL token acquisition failures (invalid_grant, wrong client secret, network errors), the Graph HTTP failures from getUserInfoFromGraph, JSON/attribute parsing errors, or NPEs from unexpected responses.","commonSituations":"Users whose accounts require MFA/conditional access (ROPC unsupported → invalid_grant); expired Azure AD client secret; wrong tenant/client-id; password wrong or expired in Azure AD; transient network failure to login.microsoftonline.com.","solutions":["Read the nested cause logged by LoggingUtils.error (the message appended after 'Invalid credentials:') to identify the real failure — e.g. invalid_grant vs. connection timeout.","If invalid_grant/MFA required: the ROPC credential flow cannot proceed for that user — have the user authenticate interactively or exempt them from conditional access, since this handler only supports direct username/password.","Validate cas.authn.azuread[0] client-id, client-secret, tenant and that the secret has not expired in the Azure portal; rotate and retry.","Verify the supplied username/password is correct and the account is not locked/expired in Azure AD.","Check network/DNS/proxy reachability to login.microsoftonline.com and graph.microsoft.com from the CAS server."],"exampleFix":"// before: users with conditional-access MFA always fail\n// Invalid credentials: invalid_grant - MFA required\n\n// after: exclude these users from conditional access or use an\n// interactive OAuth flow instead of the ROPC-based handler","handlingStrategy":"try-catch","validationCode":"// validate config before authenticating\nif (StringUtils.isAnyBlank(properties.getClientId(), properties.getClientSecret(), properties.getTenant())) {\n    throw new IllegalArgumentException(\"azuread client-id/secret/tenant must be set\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return handler.authenticateUsernamePasswordInternal(credential);\n} catch (FailedLoginException e) {\n    // 'Invalid credentials: <cause message>' — inspect the appended cause\n    LOGGER.error(\"Azure AD auth failed, root cause: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Always log/inspect the wrapped cause message — the real error (invalid_grant, timeout, 401) is appended after 'Invalid credentials:'.","Verify the account can use the ROPC flow (no MFA/conditional-access requirements) before onboarding users.","Rotate Azure AD client secrets proactively and validate tenant/client-id on each deployment.","Add a health check that acquires a token at startup to catch credential/config issues early."],"tags":["azure-ad","authentication","failed-login","msal"],"backgroundTag":"authentication-required","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"}