{"record":{"id":"56c27f628f209300","repo":"spring-projects/spring-security","slug":"abstractuserdetailsauthenticationprovider-locked","errorCode":"AbstractUserDetailsAuthenticationProvider.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/AbstractUserDetailsReactiveAuthenticationManager.java","lineNumber":77,"sourceCode":"\n\tprotected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();\n\n\tprivate PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();\n\n\tprivate ReactiveUserDetailsPasswordService userDetailsPasswordService = ReactiveUserDetailsPasswordService.NOOP;\n\n\tprivate Scheduler scheduler = Schedulers.boundedElastic();\n\n\tprivate UserDetailsChecker preAuthenticationChecks = this::defaultPreAuthenticationChecks;\n\n\tprivate UserDetailsChecker postAuthenticationChecks = this::defaultPostAuthenticationChecks;\n\n\tprivate @Nullable ReactiveCompromisedPasswordChecker compromisedPasswordChecker;\n\n\tprivate void defaultPreAuthenticationChecks(UserDetails user) {\n\t\tif (!user.isAccountNonLocked()) {\n\t\t\tthis.logger.debug(\"User account is locked\");\n\t\t\tthrow new LockedException(this.messages.getMessage(\"AbstractUserDetailsAuthenticationProvider.locked\",\n\t\t\t\t\t\"User account is locked\"));\n\t\t}\n\t\tif (!user.isEnabled()) {\n\t\t\tthis.logger.debug(\"User account is disabled\");\n\t\t\tthrow new DisabledException(\n\t\t\t\t\tthis.messages.getMessage(\"AbstractUserDetailsAuthenticationProvider.disabled\", \"User is disabled\"));\n\t\t}\n\t\tif (!user.isAccountNonExpired()) {\n\t\t\tthis.logger.debug(\"User account is expired\");\n\t\t\tthrow new AccountExpiredException(this.messages\n\t\t\t\t.getMessage(\"AbstractUserDetailsAuthenticationProvider.expired\", \"User account has expired\"));\n\t\t}\n\t}\n\n\tprivate void defaultPostAuthenticationChecks(UserDetails user) {\n\t\tif (!user.isCredentialsNonExpired()) {\n\t\t\tthis.logger.debug(\"User account credentials have expired\");\n\t\t\tthrow new CredentialsExpiredException(this.messages.getMessage(","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/core/src/main/java/org/springframework/security/authentication/AbstractUserDetailsReactiveAuthenticationManager.java#L59-L95","documentation":"AbstractUserDetailsReactiveAuthenticationManager.defaultPreAuthenticationChecks runs before password verification in reactive authentication. If UserDetails.isAccountNonLocked() returns false, it throws LockedException with message 'User account is locked' (message code AbstractUserDetailsAuthenticationProvider.locked). Authentication is aborted regardless of credentials.","triggerScenarios":"Authenticating (authenticate(Mono<Authentication>)) a UserDetails whose isAccountNonLocked() returns false — typically a custom UserDetails implementation, or a JdbcUserDetailsManager users table row with enabled/non_locked flag set to locked.","commonSituations":"Accounts locked by brute-force lockout policies; users table schema where account_non_locked column defaults to 0/false; custom UserDetails beans forgetting to override isAccountNonLocked() (default false on UserDetails itself).","solutions":["Return true from isAccountNonLocked() in your UserDetails implementation (or fix the account_non_locked flag in the user store)","Unlock the account in your user database / admin tooling","Catch LockedException in the reactive pipeline and surface a clear account-locked message to the client","If you want to skip these checks, supply a custom UserDetailsChecker via setPreAuthenticationChecks that omits the lock check"],"exampleFix":"// before\n@Override\npublic boolean isAccountNonLocked() { return locked; } // locked flag stuck false\n// after\n@Override\npublic boolean isAccountNonLocked() { return !accountLockedByAdmin(); }","handlingStrategy":"try-catch","validationCode":"if (!userDetails.isAccountNonLocked()) throw new LockedException(\"Account locked: \" + username);","typeGuard":"boolean authenticatable(UserDetails u) { return u.isAccountNonLocked() && u.isEnabled() && u.isAccountNonExpired(); }","tryCatchPattern":"authManager.authenticate(token)\n  .onErrorResume(LockedException.class, e -> Mono.error(new AuthFailure(\"ACCOUNT_LOCKED\")));","preventionTips":["Always override all UserDetails status methods; defaults are false","Sync account_non_locked flags with lockout policy state","Admin UI/tests to verify lock state before login attempts","Map LockedException to a clear API error code for clients"],"tags":["authentication","reactive","account-locked","userdetails"],"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"}