{"record":{"id":"c6507e9cc53cbbaa","repo":"spring-projects/spring-security","slug":"user-account-has-expired","errorCode":null,"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/dao/AbstractUserDetailsAuthenticationProvider.java","lineNumber":385,"sourceCode":"\n\t\t@Override\n\t\tpublic void check(UserDetails user) {\n\t\t\tif (!user.isAccountNonLocked()) {\n\t\t\t\tAbstractUserDetailsAuthenticationProvider.this.logger\n\t\t\t\t\t.debug(\"Failed to authenticate since user account is locked\");\n\t\t\t\tthrow new LockedException(AbstractUserDetailsAuthenticationProvider.this.messages\n\t\t\t\t\t.getMessage(\"AbstractUserDetailsAuthenticationProvider.locked\", \"User account is locked\"));\n\t\t\t}\n\t\t\tif (!user.isEnabled()) {\n\t\t\t\tAbstractUserDetailsAuthenticationProvider.this.logger\n\t\t\t\t\t.debug(\"Failed to authenticate since user account is disabled\");\n\t\t\t\tthrow new DisabledException(AbstractUserDetailsAuthenticationProvider.this.messages\n\t\t\t\t\t.getMessage(\"AbstractUserDetailsAuthenticationProvider.disabled\", \"User is disabled\"));\n\t\t\t}\n\t\t\tif (!user.isAccountNonExpired()) {\n\t\t\t\tAbstractUserDetailsAuthenticationProvider.this.logger\n\t\t\t\t\t.debug(\"Failed to authenticate since user account has expired\");\n\t\t\t\tthrow new AccountExpiredException(AbstractUserDetailsAuthenticationProvider.this.messages\n\t\t\t\t\t.getMessage(\"AbstractUserDetailsAuthenticationProvider.expired\", \"User account has expired\"));\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate class DefaultPostAuthenticationChecks implements UserDetailsChecker {\n\n\t\t@Override\n\t\tpublic void check(UserDetails user) {\n\t\t\tif (!user.isCredentialsNonExpired()) {\n\t\t\t\tAbstractUserDetailsAuthenticationProvider.this.logger\n\t\t\t\t\t.debug(\"Failed to authenticate since user account credentials have expired\");\n\t\t\t\tthrow new CredentialsExpiredException(AbstractUserDetailsAuthenticationProvider.this.messages\n\t\t\t\t\t.getMessage(\"AbstractUserDetailsAuthenticationProvider.credentialsExpired\",\n\t\t\t\t\t\t\t\"User credentials have expired\"));\n\t\t\t}\n\t\t}","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/core/src/main/java/org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java#L367-L403","documentation":"DefaultPreAuthenticationChecks.check() in AbstractUserDetailsAuthenticationProvider throws AccountExpiredException 'User account has expired' when UserDetails.isAccountNonExpired() returns false. The credentials may be correct but the account's validity window has ended.","triggerScenarios":"DaoAuthenticationProvider pre-authentication check on a UserDetails with isAccountNonExpired() == false.","commonSituations":"Contract or trial accounts past their end date; expiry computed from a DB date column that has passed; custom UserDetails returning false inadvertently.","solutions":["Extend the account's expiry date or set isAccountNonExpired() to return the correct value","Implement an account-renewal process for time-limited accounts","If account expiry is unused, always return true from isAccountNonExpired()","Catch AccountExpiredException in the failure handler to show an account-expired message"],"exampleFix":"// before\n@Override\npublic boolean isAccountNonExpired() { return false; }\n// after\n@Override\npublic boolean isAccountNonExpired() { return this.expiryDate == null || Instant.now().isBefore(this.expiryDate); }","handlingStrategy":"try-catch","validationCode":"UserDetails user = uds.loadUserByUsername(username);\nif (!user.isAccountNonExpired()) { throw new IllegalStateException(\"Account expired: \" + username); }","typeGuard":"boolean isLoginAllowed(UserDetails u) { return u.isAccountNonExpired(); }","tryCatchPattern":"try { authMgr.authenticate(token); } catch (AccountExpiredException e) { return ResponseEntity.status(403).body(\"Account has expired.\"); }","preventionTips":["Use nullable expiry dates when expiry is optional","Notify users before expiry","Cover all UserDetails status flags in unit tests"],"tags":["spring-security","authentication","account-expired"],"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"}