{"record":{"id":"aa3faf6dad583dc4","repo":"spring-projects/spring-security","slug":"user-credentials-have-expired-aa3faf","errorCode":null,"errorMessage":"User credentials have expired","messagePattern":"User credentials have expired","errorType":"exception","errorClass":"CredentialsExpiredException","httpStatus":null,"severity":"error","filePath":"ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java","lineNumber":265,"sourceCode":"\t\t}\n\t}\n\n\tprivate int parseSubErrorCode(@Nullable String message) {\n\t\tif (message == null) {\n\t\t\treturn -1;\n\t\t}\n\t\tMatcher matcher = SUB_ERROR_CODE.matcher(message);\n\t\tif (matcher.matches()) {\n\t\t\treturn Integer.parseInt(matcher.group(1), 16);\n\t\t}\n\t\treturn -1;\n\t}\n\n\tprivate void raiseExceptionForErrorCode(int code, NamingException exception) {\n\t\tString hexString = Integer.toHexString(code);\n\t\tThrowable cause = new ActiveDirectoryAuthenticationException(hexString, exception.getMessage(), exception);\n\t\tswitch (code) {\n\t\t\tcase PASSWORD_EXPIRED -> throw new CredentialsExpiredException(this.messages\n\t\t\t\t.getMessage(\"LdapAuthenticationProvider.credentialsExpired\", \"User credentials have expired\"), cause);\n\t\t\tcase ACCOUNT_DISABLED -> throw new DisabledException(\n\t\t\t\t\tthis.messages.getMessage(\"LdapAuthenticationProvider.disabled\", \"User is disabled\"), cause);\n\t\t\tcase ACCOUNT_EXPIRED -> throw new AccountExpiredException(\n\t\t\t\t\tthis.messages.getMessage(\"LdapAuthenticationProvider.expired\", \"User account has expired\"), cause);\n\t\t\tcase ACCOUNT_LOCKED -> throw new LockedException(\n\t\t\t\t\tthis.messages.getMessage(\"LdapAuthenticationProvider.locked\", \"User account is locked\"), cause);\n\t\t\tdefault -> throw badCredentials(cause);\n\t\t}\n\t}\n\n\tprivate String subCodeToLogMessage(int code) {\n\t\treturn switch (code) {\n\t\t\tcase USERNAME_NOT_FOUND -> \"User was not found in directory\";\n\t\t\tcase INVALID_PASSWORD -> \"Supplied password was invalid\";\n\t\t\tcase NOT_PERMITTED -> \"User not permitted to logon at this time\";\n\t\t\tcase PASSWORD_EXPIRED -> \"Password has expired\";\n\t\t\tcase ACCOUNT_DISABLED -> \"Account is disabled\";","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java#L247-L283","documentation":"ActiveDirectoryLdapAuthenticationProvider maps AD bind-failure sub-error codes to Spring Security exceptions. When AD returns error 49 (data 532) meaning the user's password has expired, raiseExceptionForErrorCode throws CredentialsExpiredException with message 'User credentials have expired', wrapping the ActiveDirectoryAuthenticationException as the cause.","triggerScenarios":"authenticate() -> handleBindException() -> raiseExceptionForErrorCode(PASSWORD_EXPIRED), triggered when an LDAP bind against Active Directory fails with error code 532 (ERROR_PASSWORD_EXPIRED) during bindAuthentication.","commonSituations":"AD domain password policy's max password age elapsed for the user; service accounts whose passwords were not rotated; users authenticating who must change their password at next logon after expiration.","solutions":["The user must change their AD password (via Ctrl+Alt+Del on a domain machine, self-service portal, or admin reset).","For service accounts, rotate the configured password and update the application's credentials.","Admin can set the password to not expire for the account if appropriate (Set-AdUser -PasswordNeverExpires).","Catch CredentialsExpiredException in your failure handler and redirect users to a password-change flow."],"exampleFix":"// before: generic failure handler\ncatch (BadCredentialsException e) { return \"login?error\"; }\n// after: handle expired credentials distinctly\ncatch (CredentialsExpiredException e) { return \"redirect:/password/change-expired\"; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return authenticationManager.authenticate(token);\n} catch (CredentialsExpiredException e) {\n    return \"redirect:/password/expired\"; // send user to change-password flow\n}","preventionTips":["Monitor AD password expiry for service accounts and rotate proactively.","Surface 'finestGrain' error codes from ActiveDirectoryAuthenticationException in logs.","Provide a self-service password change flow for expired credentials.","Consider 'warn days' notifications before max password age."],"tags":["ldap","active-directory","credentials-expired","spring-security"],"backgroundTag":"jwt-token-expired","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}