{"record":{"id":"ce38e03c7d3045b1","repo":"spring-projects/spring-security","slug":"accountstatususerdetailschecker-locked","errorCode":"AccountStatusUserDetailsChecker.locked","errorMessage":"User account is locked","messagePattern":"User account is locked","errorType":"exception","errorClass":"LockedException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/springframework/security/authentication/AccountStatusUserDetailsChecker.java","lineNumber":46,"sourceCode":"import org.springframework.util.Assert;\n\n/**\n * A {@link UserDetailsChecker} that verifies the account status flags on a\n * {@link UserDetails}.\n *\n * @author Luke Taylor\n */\npublic class AccountStatusUserDetailsChecker implements UserDetailsChecker, MessageSourceAware {\n\n\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\tprotected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();\n\n\t@Override\n\tpublic void check(UserDetails user) {\n\t\tif (!user.isAccountNonLocked()) {\n\t\t\tthis.logger.debug(\"Failed to authenticate since user account is locked\");\n\t\t\tthrow new LockedException(\n\t\t\t\t\tthis.messages.getMessage(\"AccountStatusUserDetailsChecker.locked\", \"User account is locked\"));\n\t\t}\n\t\tif (!user.isEnabled()) {\n\t\t\tthis.logger.debug(\"Failed to authenticate since user account is disabled\");\n\t\t\tthrow new DisabledException(\n\t\t\t\t\tthis.messages.getMessage(\"AccountStatusUserDetailsChecker.disabled\", \"User is disabled\"));\n\t\t}\n\t\tif (!user.isAccountNonExpired()) {\n\t\t\tthis.logger.debug(\"Failed to authenticate since user account is expired\");\n\t\t\tthrow new AccountExpiredException(\n\t\t\t\t\tthis.messages.getMessage(\"AccountStatusUserDetailsChecker.expired\", \"User account has expired\"));\n\t\t}\n\t\tif (!user.isCredentialsNonExpired()) {\n\t\t\tthis.logger.debug(\"Failed to authenticate since user account credentials have expired\");\n\t\t\tthrow new CredentialsExpiredException(this.messages\n\t\t\t\t.getMessage(\"AccountStatusUserDetailsChecker.credentialsExpired\", \"User credentials have expired\"));\n\t\t}\n\t}","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/core/src/main/java/org/springframework/security/authentication/AccountStatusUserDetailsChecker.java#L28-L64","documentation":"AccountStatusUserDetailsChecker.check validates a UserDetails' account status flags in order (locked, disabled, expired, credentials expired) and throws the corresponding AuthenticationException for the first failed flag. With message code AccountStatusUserDetailsChecker.locked it throws LockedException 'User account is locked' when isAccountNonLocked() is false.","triggerScenarios":"Calling check(user) (e.g. from a UserDetailsService-based login flow or DaoAuthenticationProvider's pre-auth checks) with a UserDetails whose isAccountNonLocked() returns false.","commonSituations":"Lockout policies locking accounts after failed attempts; database flag account_non_locked=0; custom UserDetails not overriding isAccountNonLocked(); running check() manually in custom authentication code.","solutions":["Fix the underlying status: unlock the account in the user store or correct isAccountNonLocked() in your UserDetails","If the interface method was not overridden, implement it — all UserDetails default status methods return false","Catch LockedException around check()/authentication and present an account-locked UX flow","Audit all four flags (locked, enabled, accountNonExpired, credentialsNonExpired) since check() reports only the first failure"],"exampleFix":"// before\nuserDetailsChecker.check(user); // throws LockedException\n// after\ntry { userDetailsChecker.check(user); }\ncatch (LockedException e) { auditLog.record(\"locked\", user.getUsername()); throw e; }","handlingStrategy":"try-catch","validationCode":"if (!user.isAccountNonLocked()) throw new LockedException(\"locked: \" + user.getUsername());","typeGuard":"boolean statusOk(UserDetails u) { return u.isAccountNonLocked() && u.isEnabled() && u.isAccountNonExpired() && u.isCredentialsNonExpired(); }","tryCatchPattern":"try { checker.check(user); }\ncatch (LockedException | DisabledException | AccountExpiredException | CredentialsExpiredException e) {\n  throw new BadCredentialsException(\"account-status\", e);\n}","preventionTips":["Validate all four status flags before calling check(); it stops at the first failure","Implement every UserDetails method — defaults are false","Keep an unlock mechanism (admin endpoint/scheduled job)","Log which flag failed for support diagnostics"],"tags":["authentication","userdetails","account-locked","account-status"],"backgroundTag":"authentication-required","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"}