{"record":{"id":"c02e50a3e6090f1a","repo":"spring-projects/spring-security","slug":"abstractuserdetailsauthenticationprovider-expired","errorCode":"AbstractUserDetailsAuthenticationProvider.expired","errorMessage":"User account has expired","messagePattern":"User account has expired","errorType":"exception","errorClass":"AccountExpiredException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/springframework/security/authentication/AbstractUserDetailsReactiveAuthenticationManager.java","lineNumber":87,"sourceCode":"\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(\n\t\t\t\t\t\"AbstractUserDetailsAuthenticationProvider.credentialsExpired\", \"User credentials have expired\"));\n\t\t}\n\t}\n\n\t@Override\n\tpublic Mono<Authentication> authenticate(Authentication authentication) {\n\t\tString username = authentication.getName();\n\t\tString presentedPassword = (authentication.getCredentials() != null)\n\t\t\t\t? authentication.getCredentials().toString() : null;\n\t\t// @formatter:off","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/core/src/main/java/org/springframework/security/authentication/AbstractUserDetailsReactiveAuthenticationManager.java#L69-L105","documentation":"defaultPreAuthenticationChecks throws AccountExpiredException with 'User account has expired' (message code AbstractUserDetailsAuthenticationProvider.expired) when UserDetails.isAccountNonExpired() returns false. This is a pre-authentication check in the reactive authentication manager; the account's validity period has ended.","triggerScenarios":"authenticate() on a UserDetails whose isAccountNonExpired() returns false — typically accounts with an expiry date in the past (e.g. temporary/contract accounts) or custom UserDetails not overriding isAccountNonExpired() (default false).","commonSituations":"Time-limited accounts (contractors, trials) passing their expiry date; custom User implementations omitting isAccountNonExpired(); test fixtures with hardcoded expiry timestamps now in the past.","solutions":["Return true from isAccountNonExpired() (or extend the expiry date in the user store) for accounts that should remain valid","Implement a renewal process updating the account expiry timestamp","Catch AccountExpiredException and prompt the user to renew/reactivate","Check your UserDetails overrides all four status methods; interface defaults are all false"],"exampleFix":"// before\n@Override public boolean isAccountNonExpired() { return false; }\n// after\n@Override public boolean isAccountNonExpired() { return expiryDate.isAfter(Instant.now()); }","handlingStrategy":"try-catch","validationCode":"if (!userDetails.isAccountNonExpired()) throw new AccountExpiredException(\"Account expired: \" + username);","typeGuard":"boolean accountCurrent(UserDetails u) { return u.isAccountNonExpired(); }","tryCatchPattern":"authManager.authenticate(token)\n  .onErrorResume(AccountExpiredException.class, e -> Mono.error(new AuthFailure(\"ACCOUNT_EXPIRED\")));","preventionTips":["Compute account expiry from a real date field, not a constant false","Add renewal/extension workflows for time-limited accounts","Monitor expiry dates approaching to warn users","Override all UserDetails methods; interface defaults return false"],"tags":["authentication","reactive","account-expired","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"}