How does httpBasic() differ from formLogin(), and what does BasicAuthenticationFilter do?
answer
- Basic = Authorization header every request; form = session + cookie
- BasicAuthenticationFilter decodes base64(user:pass)
- 401 + WWW-Authenticate: Basic realm=...
- form login = 302 redirect to /login
- base64 != encryption -> require TLS
basics
~20 shttpBasic() reads credentials from the 'Authorization: Basic' header on every request; formLogin() uses an HTML form and a server session. Basic is stateless and good for APIs/scripts; form login is stateful and good for browsers.
solid answer
~40 sBoth authenticate username/password, but through different mechanisms. formLogin() posts a form once and stores the authenticated user in the session — stateful, browser-friendly, with redirects. httpBasic() registers BasicAuthenticationFilter, which on every request reads the 'Authorization: Basic base64(user:pass)' header, decodes it, builds a UsernamePasswordAuthenticationToken, and calls the AuthenticationManager. Basic is effectively stateless: there's no login page or redirect, and clients (curl, HTTP clients) resend credentials each time. When an unauthenticated request hits a protected resource, Basic's BasicAuthenticationEntryPoint returns 401 with a 'WWW-Authenticate: Basic realm=...' header, prompting the client. Form login instead redirects the browser to the login page via LoginUrlAuthenticationEntryPoint. Basic must run over TLS since credentials are only base64-encoded, not encrypted.
code
java · 15 lines@Bean
SecurityFilterChain api(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**")
.authorizeHttpRequests(a -> a.anyRequest().authenticated())
.httpBasic(basic -> basic
.realmName("KataJob API"))
// Basic is stateless: don't create sessions for API traffic
.sessionManagement(s -> s
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.csrf(csrf -> csrf.disable()); // safe: no cookies/sessions here
return http.build();
}
// Client: curl -u alice:secret https://host/api/things
// Header sent: Authorization: Basic YWxpY2U6c2VjcmV0go deeper
Know Basic sends credentials in a header every request while form login uses a session; Basic needs HTTPS.
Explain BasicAuthenticationFilter decoding, the 401/WWW-Authenticate challenge vs 302 redirect, and statelessness.
Discuss combining both mechanisms, session policy, CSRF implications, and entry-point selection.
Weigh Basic vs token auth for service-to-service traffic, credential exposure surface, and rotation/secret-management concerns.
## The two mechanisms side by side Both `formLogin()` and `httpBasic()` authenticate a **username and password**, but the *transport* and *lifecycle* differ. ### formLogin() - Credentials come from **HTML form parameters** in a `POST /login`. - Processed by `UsernamePasswordAuthenticationFilter`. - **Stateful**: the result is stored in the session (`HttpSessionSecurityContextRepository`); the browser then rides a `JSESSIONID` cookie. - Unauthenticated access to a protected page triggers a **redirect** to the login page (`LoginUrlAuthenticationEntryPoint`, HTTP 302). - Meant for **human browser users**. ### httpBasic() - Credentials come from the **`Authorization` HTTP header**: `Authorization: Basic <base64(username:password)>`. - Processed by **`BasicAuthenticationFilter`**. - Effectively **stateless** per request: the client (curl, Postman, another service) re-sends the header every time. There is no login page and no redirect. - Unauthenticated access triggers **`BasicAuthenticationEntryPoint`**, which returns **HTTP 401 Unauthorized** with a **`WWW-Authenticate: Basic realm="..."`** response header. A browser reacts to this by popping up its native credential dialog; a programmatic client reads it and retries with the header. - Meant for **machine-to-machine / API / scripting** access. ## What BasicAuthenticationFilter does, step by step 1. Looks for an `Authorization` header starting with `Basic `. 2. If absent, it does nothing and passes the request down the chain (the request may later be rejected by authorization, triggering the entry point). 3. If present, it **Base64-decodes** the value into `username:password`, splitting on the first colon. 4. Builds an **unauthenticated** `UsernamePasswordAuthenticationToken` and calls the `AuthenticationManager`. 5. On success it stores the authentication in the `SecurityContext` and continues the chain. In Spring Security 6, Basic does **not** persist to the session by default (each request re-authenticates from the header); you can opt into caching. 6. On failure (`AuthenticationException`) it delegates to its configured `AuthenticationEntryPoint` (default `BasicAuthenticationEntryPoint`) to send the 401 challenge, and does **not** continue the chain. ## Security note: base64 is NOT encryption Base64 is trivially reversible. HTTP Basic exposes credentials to anyone who can read the request, so it **must** run over **HTTPS/TLS**. Because credentials travel on every request, the attack surface for interception is larger than a one-time form post. ## Can you enable both? Yes — `http.formLogin(...).httpBasic(...)` registers both filters in the same chain. A browser hitting a page gets redirected to the form; an API client sending the Basic header authenticates directly. When both are on, Spring must decide **which entry point to use** for unauthenticated requests (see the delegating entry point question). ## When to use which - **Form login:** server-rendered web UIs for humans. - **HTTP Basic:** internal service calls, actuator endpoints, quick API auth, CI scripts — always behind TLS. - For public SPAs/mobile APIs, prefer token-based (JWT/OAuth2) over Basic to avoid holding raw credentials client-side. ## Gotchas - CSRF: Basic (stateless, header-based) is not vulnerable to CSRF the way cookie/session auth is; but if you mix session state, keep CSRF on for the browser flow. - Browsers **cache** Basic credentials for the session, making 'logout' awkward. - The realm string is cosmetic but shows in the browser dialog; set it via a custom `BasicAuthenticationEntryPoint`.
- Why should HTTP Basic always be used over HTTPS?The credentials are only Base64-encoded, which is reversible, not encrypted. Over plain HTTP anyone on the path can decode username and password. TLS encrypts the whole request including the Authorization header, and Basic re-sends it on every request, so exposure without TLS is severe.
- If both httpBasic() and formLogin() are enabled, what happens when an API client without credentials calls a protected URL?It depends on which AuthenticationEntryPoint Spring selects. With both mechanisms, a DelegatingAuthenticationEntryPoint chooses based on request matchers/headers (e.g. Accept or X-Requested-With) — ideally returning 401 with WWW-Authenticate for API/XHR clients and a 302 redirect to the form for browsers.
saying these in an interview costs you the question
- Calling base64 in Basic auth 'encryption'.
- Saying HTTP Basic is stateful and uses a login page.
- Believing Basic auth is CSRF-vulnerable the same way cookie/session auth is.