{"record":{"id":"7caf92e3f6f61e3f","repo":"spring-projects/spring-security","slug":"the-login-page-is-being-protected-by-the-filter-ch","errorCode":null,"errorMessage":"The login page is being protected by the filter chain, but you don't appear to have anonymous authentication enabled. This is almost certainly an error.","messagePattern":"The login page is being protected by the filter chain, but you don't appear to have anonymous authentication enabled\\. This is almost certainly an error\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java","lineNumber":226,"sourceCode":"\t\t\t// May happen legitimately if a filter-chain request matcher requires more\n\t\t\t// request data than that provided\n\t\t\t// by the dummy request used when creating the filter invocation.\n\t\t\tthis.logger.info(\"Failed to obtain filter chain information for the login page. Unable to complete check.\");\n\t\t}\n\t\tif (filters == null || filters.isEmpty()) {\n\t\t\tthis.logger.debug(\"Filter chain is empty for the login page\");\n\t\t\treturn;\n\t\t}\n\t\tif (getFilter(DefaultLoginPageGeneratingFilter.class, filters) != null) {\n\t\t\tthis.logger.debug(\"Default generated login page is in use\");\n\t\t\treturn;\n\t\t}\n\t\tif (checkLoginPageIsPublic(filters, loginRequest)) {\n\t\t\treturn;\n\t\t}\n\t\tAnonymousAuthenticationFilter anonymous = getFilter(AnonymousAuthenticationFilter.class, filters);\n\t\tif (anonymous == null) {\n\t\t\tthis.logger.warn(\"The login page is being protected by the filter chain, but you don't appear to have\"\n\t\t\t\t\t+ \" anonymous authentication enabled. This is almost certainly an error.\");\n\t\t\treturn;\n\t\t}\n\t\t// Simulate an anonymous access with the supplied attributes.\n\t\tAnonymousAuthenticationToken token = new AnonymousAuthenticationToken(\"key\", anonymous.getPrincipal(),\n\t\t\t\tanonymous.getAuthorities());\n\t\tSupplier<Boolean> check = deriveAnonymousCheck(filters, loginRequest, token);\n\t\ttry {\n\t\t\tboolean allowed = check.get();\n\t\t\tif (!allowed) {\n\t\t\t\tthis.logger.warn(\"Anonymous access to the login page doesn't appear to be enabled. \"\n\t\t\t\t\t\t+ \"This is almost certainly an error. Please check your configuration allows unauthenticated \"\n\t\t\t\t\t\t+ \"access to the configured login page. (Simulated access was rejected)\");\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// May happen legitimately if a filter-chain request matcher requires more\n\t\t\t// request data than that provided","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java#L208-L244","documentation":"DefaultFilterChainValidator.checkLoginPageIsntProtected verifies that the configured login page can be reached without authentication. If no AnonymousAuthenticationFilter is present in the chain and the login page is not otherwise public, it warns that the login page is protected by the filter chain without anonymous authentication, which almost always breaks login (redirect loop back to the login page). This is a logged warning, not an exception.","triggerScenarios":"Calling validate() on a FilterChainProxy when: a login page is configured (formLogin().loginPage(...)), the page's request matcher is not matched by any permitAll rule, and the filter chain lacks AnonymousAuthenticationFilter (anonymous().disabled() or filter removed).","commonSituations":"Disabling anonymous authentication while using a custom login page; a permitAll rule whose matcher does not actually cover the login URL (typo, wrong HTTP method, context-path mismatch); copying a config that removed anonymous support.","solutions":["Re-enable anonymous authentication: remove anonymous().disable() / restore the AnonymousAuthenticationFilter.","Add an explicit permitAll rule for the login page: authorizeHttpRequests().requestMatchers(\"/login\").permitAll().","Verify the configured loginPage URL matches the actual protected-request matcher (context path included).","Ensure a LoginUrlAuthenticationEntryPoint is used so unauthenticated users are redirected, not rejected."],"exampleFix":"// before\nhttp.authorizeHttpRequests(a -> a.anyRequest().authenticated())\n    .formLogin(f -> f.loginPage(\"/login\"))\n    .anonymous(a -> a.disable());\n// after\nhttp.authorizeHttpRequests(a -> a.requestMatchers(\"/login\").permitAll()\n        .anyRequest().authenticated())\n    .formLogin(f -> f.loginPage(\"/login\"));","handlingStrategy":"validation","validationCode":"// assert login page is permitted in tests\nmockMvc.perform(get(\"/login\"))\n    .andExpect(status().isOk());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair a custom loginPage with requestMatchers(\"/login\").permitAll().","Never call anonymous().disable() unless the whole config is stateless/token-based.","Add an integration test fetching the login page anonymously.","Watch for the DefaultFilterChainValidator warnings at startup in CI logs."],"tags":["spring-security","filter-chain","anonymous-authentication","login-page"],"backgroundTag":"invalid-config-value","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}