{"record":{"id":"4b96d85259046407","repo":"spring-projects/spring-security","slug":"user-account-has-expired-4b96d8","errorCode":null,"errorMessage":"User account has expired","messagePattern":"User account has expired","errorType":"exception","errorClass":"AccountExpiredException","httpStatus":null,"severity":"error","filePath":"ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java","lineNumber":269,"sourceCode":"\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\";\n\t\t\tcase ACCOUNT_EXPIRED -> \"Account expired\";\n\t\t\tcase PASSWORD_NEEDS_RESET -> \"User must reset password\";\n\t\t\tcase ACCOUNT_LOCKED -> \"Account locked\";\n\t\t\tdefault -> \"Unknown (error code \" + Integer.toHexString(code) + \")\";","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java#L251-L287","documentation":"ActiveDirectoryLdapAuthenticationProvider maps AD bind-failure sub-codes to Spring Security exceptions. When AD bind fails with sub-error 701 (ACCOUNT_EXPIRED, account validity elapsed), raiseExceptionForErrorCode throws AccountExpiredException('User account has expired') wrapping the ActiveDirectoryAuthenticationException as cause.","triggerScenarios":"authenticate() -> handleBindException() -> raiseExceptionForErrorCode(ACCOUNT_EXPIRED), raised when the LDAP bind against AD fails with sub-error code 701 indicating the account's accountExpires date has passed.","commonSituations":"Temporary/contractor accounts with an accountExpires date that elapsed; accounts created with an expiration window never extended; seasonal accounts auto-expiring per policy.","solutions":["Ask an AD administrator to extend or clear the account expiration date (Set-ADAccountExpiration or set accountExpires to never).","Confirm the correct account is being used.","Catch AccountExpiredException in your auth failure handler to surface an account-expired message.","For service accounts, set the account to never expire and control access via groups instead."],"exampleFix":"// before\ncatch (BadCredentialsException e) { return \"login?error\"; }\n// after\ncatch (AccountExpiredException e) { return \"redirect:/account/expired\"; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return authenticationManager.authenticate(token);\n} catch (AccountExpiredException e) {\n    return \"redirect:/account/expired\";\n}","preventionTips":["Audit accounts with accountExpires set and renew before expiry.","For service accounts, prefer never-expiring accounts controlled by group membership.","Catch AccountExpiredException distinctly to guide user to renewal.","Log ActiveDirectoryAuthenticationException sub-code (data 701) for audit."],"tags":["ldap","active-directory","account-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"}