{"record":{"id":"c282e1d318840538","repo":"spring-projects/spring-security","slug":"accountstatususerdetailschecker-expired","errorCode":"AccountStatusUserDetailsChecker.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/AccountStatusUserDetailsChecker.java","lineNumber":56,"sourceCode":"\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}\n\n\t/**\n\t * Sets the {@link MessageSource} used to resolve exception messages.\n\t * @since 5.2\n\t */\n\t@Override\n\tpublic void setMessageSource(MessageSource messageSource) {\n\t\tAssert.notNull(messageSource, \"messageSource cannot be null\");\n\t\tthis.messages = new MessageSourceAccessor(messageSource);\n\t}","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/core/src/main/java/org/springframework/security/authentication/AccountStatusUserDetailsChecker.java#L38-L74","documentation":"AccountStatusUserDetailsChecker.check() throws AccountExpiredException with message 'User account has expired' when UserDetails.isAccountNonExpired() returns false. The account exists and is enabled but its validity period has ended.","triggerScenarios":"Authentication of a UserDetails whose isAccountNonExpired() returns false, typically checked during DaoAuthenticationProvider's post-authentication checks.","commonSituations":"Accounts with a fixed contract/lifetime (expiryDate in DB); loading user with expired-by-date flag; custom UserDetails hardcoding accountNonExpired=false; time-based account policies in enterprise systems.","solutions":["Extend the account's expiry date in the user store or set isAccountNonExpired() to return true if expiry is not intended","Implement renewal workflow so expired accounts are re-validated and extended","If you don't use account expiry, always return true from isAccountNonExpired() in your UserDetails","Catch AccountExpiredException in your failure handler to render an 'account expired, contact support' message"],"exampleFix":"// before\n@Override\npublic boolean isAccountNonExpired() { return LocalDate.now().isBefore(expiryDate); } // expired\n// after\n@Override\npublic boolean isAccountNonExpired() { return expiryDate == null || LocalDate.now().isBefore(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 expired. Please renew.\"); }","preventionTips":["Model expiry as an optional/nullable date so unused expiry never rejects users","Alert users before their account expiry date","Unit-test UserDetails implementations for all four status flags"],"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"}