What is anonymous authentication in Spring Security, and what does the SecurityContext hold for an unauthenticated request?
answer
- Placeholder token, not null
- AnonymousAuthenticationFilter at chain end
- principal='anonymousUser', ROLE_ANONYMOUS
- authenticated=true but TrustResolver says anonymous
basics
~20 sFor a request with no login, Spring Security still puts a placeholder 'anonymous' user into the SecurityContext instead of leaving it empty. So code can always assume an Authentication object exists rather than handling null.
solid answer
~40 sSpring Security never leaves the SecurityContext empty for a request that reached the filter chain without authenticating. The AnonymousAuthenticationFilter, near the end of the chain, checks whether the SecurityContextHolder already holds an Authentication; if not, it inserts an AnonymousAuthenticationToken. That token has a principal (default string 'anonymousUser'), one authority (default ROLE_ANONYMOUS), and is marked authenticated=true, so downstream code can uniformly call getAuthentication() without null checks. It represents 'this is not a logged-in user' rather than 'no information at all'. This is why an unauthenticated request still has a non-null Authentication and why rules such as isAnonymous() work. Crucially, AuthenticationTrustResolver still classifies anonymous as unauthenticated, so anything requiring real authentication is denied and triggers the AuthenticationEntryPoint.
code
java · 6 lines// Downstream code can rely on a non-null Authentication
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// For an unauthenticated request this is an AnonymousAuthenticationToken:
// auth.getName() -> "anonymousUser"
// auth.getAuthorities() -> [ROLE_ANONYMOUS]
// auth.isAuthenticated() -> true (but trust resolver treats it as anonymous)go deeper
Know that unauthenticated requests still get a placeholder Authentication instead of null.
Explain the token defaults (anonymousUser, ROLE_ANONYMOUS) and that the filter sits at the chain end.
Explain why authenticated=true yet still treated as unauthenticated via AuthenticationTrustResolver.
Discuss enabling/disabling trade-offs, null-handling contracts, and how it interacts with entry points and stateless APIs.
**The problem it solves.** Every request flows through the Spring Security filter chain, and application code reads the current user via `SecurityContextHolder.getContext().getAuthentication()`. If unauthenticated requests left this `null`, every consumer would need a null check. Anonymous authentication removes that special case: even a request with no credentials gets a *placeholder* `Authentication`. **Key classes.** - `AnonymousAuthenticationFilter` — sits near the end of the chain (after the real authentication filters). If the context still has no `Authentication`, it creates and stores an anonymous token. - `AnonymousAuthenticationToken` — the placeholder token. Constructed with a `key`, a `principal` (default `"anonymousUser"`), and authorities (default `ROLE_ANONYMOUS`). Its `isAuthenticated()` returns `true`. - `AuthenticationTrustResolver` (default `AuthenticationTrustResolverImpl`) — the thing that decides whether an `Authentication` is 'really' authenticated. `isAnonymous()` returns true when the token is an `AnonymousAuthenticationToken`, so authorization treats anonymous as *not* logged in. **Why authenticated=true but still 'unauthenticated'.** The `authenticated` flag is `true` only so the token is a well-formed, usable `Authentication`. Whether a rule like `authenticated()` passes is decided by the trust resolver, not by the flag — and the resolver reports anonymous tokens as anonymous. So `.authenticated()` and `@PreAuthorize("isAuthenticated()")` both reject anonymous requests. **In Boot.** With Spring Boot's default security, anonymous is enabled automatically; you rarely configure it explicitly. You only touch it to change the key/principal/authorities or to disable it (`http.anonymous(AbstractHttpConfigurer::disable)`), which makes the context hold `null` again for unauthenticated requests. **When it matters.** Method-level SpEL such as `isAnonymous()`, audit logging that reads the principal, and code that always expects a non-null `Authentication`.
- If anonymous auth marks the token authenticated=true, why does an endpoint secured with authenticated() still reject an anonymous request?Because access decisions use AuthenticationTrustResolver, not the boolean flag. The resolver reports AnonymousAuthenticationToken as anonymous, so authenticated() / isAuthenticated() fail and the AuthenticationEntryPoint is triggered.
- What happens to getAuthentication() if you disable anonymous authentication?For unauthenticated requests the SecurityContext holds null again, so consumers must null-check. AnonymousAuthenticationFilter no longer runs to insert a placeholder.
saying these in an interview costs you the question
- Saying the SecurityContext is null for unauthenticated requests when anonymous is enabled
- Claiming authenticated=true means the anonymous user passes authenticated() checks
- Confusing anonymous (a placeholder identity) with no filter chain at all