What does formLogin() enable in Spring Security, and what is the role of UsernamePasswordAuthenticationFilter?
answer
- formLogin -> UsernamePasswordAuthenticationFilter
- POST /login reads username/password params
- builds unauthenticated UsernamePasswordAuthenticationToken
- AuthenticationManager verifies; stored in session (stateful)
- SavedRequest success handler, /login?error on failure
basics
~10 sformLogin() turns on a browser login form. Spring adds UsernamePasswordAuthenticationFilter, which intercepts the POST to /login, reads the username and password fields, and asks the AuthenticationManager to verify them.
solid answer
~40 sformLogin() configures form-based authentication for browser clients. It registers UsernamePasswordAuthenticationFilter, which by default intercepts POST /login, extracts the 'username' and 'password' request parameters, wraps them in an unauthenticated UsernamePasswordAuthenticationToken, and hands it to the AuthenticationManager. On success the resulting authenticated token is stored in the SecurityContext (persisted in the HTTP session via SecurityContextRepository) and the SavedRequestAwareAuthenticationSuccessHandler redirects to the originally requested URL. On failure it redirects to /login?error. GET /login renders a default auto-generated form unless you specify a custom loginPage. Form login is stateful — subsequent requests are recognized by the session, not re-sent credentials. It is the standard choice for server-rendered web apps.
code
java · 19 lines@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/css/**").permitAll()
.anyRequest().authenticated())
.formLogin(form -> form
.loginPage("/login") // custom GET page
.loginProcessingUrl("/login") // POST target for the form
.usernameParameter("email") // rename the field
.defaultSuccessUrl("/dashboard", true)
.failureUrl("/login?error"));
return http.build();
}
}go deeper
Know that formLogin() gives a login form and that a filter checks username/password against the AuthenticationManager.
Explain the token flow, default success/failure handlers, and that state lives in the session via SecurityContextRepository.
Discuss customizing loginProcessingUrl, parameter names, handlers, and the CSRF/saved-request interactions.
Reason about when form login is the wrong fit (stateless APIs), session-fixation protection, and coexistence with other auth mechanisms in one filter chain.
## What formLogin() is `formLogin()` is a DSL method on `HttpSecurity` (Spring Security's Java/Kotlin configuration builder) that enables **form-based authentication** — the classic username/password HTML form flow used by browser-based web apps. Calling `http.formLogin(Customizer.withDefaults())` wires up: - A **default login page** served at `GET /login` (an auto-generated HTML form) unless you override it with `.loginPage("/my-login")`. - A **`UsernamePasswordAuthenticationFilter`** that processes the form submission at `POST /login` (the *login processing URL*). ## UsernamePasswordAuthenticationFilter This filter extends `AbstractAuthenticationProcessingFilter`. When a request matches its `RequestMatcher` (by default `POST /login`), it: 1. Calls `attemptAuthentication(...)`, which reads the `username` and `password` **request parameters** (names configurable via `.usernameParameter(...)` / `.passwordParameter(...)`). 2. Builds an **unauthenticated** `UsernamePasswordAuthenticationToken(username, password)` — a `Principal`/credentials pair with `authenticated=false`. 3. Passes that token to the `AuthenticationManager` (typically a `ProviderManager` delegating to a `DaoAuthenticationProvider`, which loads the user via `UserDetailsService` and checks the password with the `PasswordEncoder`). 4. If the manager returns an **authenticated** token, `successfulAuthentication(...)` runs: it stores the token in the `SecurityContext`, persists that context through the `SecurityContextRepository` (default `HttpSessionSecurityContextRepository`, so the login survives across requests via the session), fires an `InteractiveAuthenticationSuccessEvent`, and invokes the `AuthenticationSuccessHandler`. 5. If the manager throws an `AuthenticationException`, `unsuccessfulAuthentication(...)` runs: it clears the context and invokes the `AuthenticationFailureHandler`. ## Defaults you get for free - **Login processing URL:** `POST /login`. - **Success handler:** `SavedRequestAwareAuthenticationSuccessHandler` — redirects to the URL the user originally tried to reach before being bounced to login (the *saved request*), falling back to `/`. - **Failure handler:** `SimpleUrlAuthenticationFailureHandler` — redirects to `/login?error`. - **Logout:** `/logout` is enabled separately by default. ## Stateful by nature Form login is **stateful**: the browser sends credentials **once**, and the authenticated context is stored server-side in the session. The browser then carries a `JSESSIONID` cookie; each later request is recognized without re-submitting the password. This contrasts with HTTP Basic, where the client re-sends credentials on every request. ## When to use it Use form login for **server-rendered, browser-facing web applications** where a friendly HTML login page and session-based auth are appropriate. For pure APIs or SPAs you would more often use token-based auth (JWT/OAuth2) or HTTP Basic for machine clients. ## Common gotchas - The **default `/login` page** disappears once you set a custom `.loginPage(...)` — you must then render that page yourself and permit access to it. - CSRF protection is **on by default**; the login form must include the CSRF token, or the POST is rejected. - The filter matches only its configured method+path; a mismatched form `action` silently 404s or bypasses login.
- How does the app remember the user after a successful form login?The authenticated token is placed in the SecurityContext and persisted by the SecurityContextRepository — by default HttpSessionSecurityContextRepository, which stores it in the HTTP session. The browser's JSESSIONID cookie then identifies the session on later requests, so credentials are not re-sent.
- Why might a valid username/password still fail to log in with a 403 on POST /login?CSRF protection is enabled by default. If the login form omits the CSRF token (_csrf), Spring rejects the POST before authentication runs. The fix is to include the token in the form (Thymeleaf/JSP tag libs add it automatically).
saying these in an interview costs you the question
- Claiming form login is stateless / re-sends credentials each request (that's HTTP Basic).
- Thinking the default /login page still works after setting a custom loginPage.
- Saying UsernamePasswordAuthenticationFilter checks the password itself (the AuthenticationManager/provider does).