What is the ExceptionTranslationFilter and what job does it do in the Spring Security filter chain?
answer
- try/catch around downstream chain
- only AuthenticationException + AccessDeniedException
- EntryPoint = start auth; AccessDeniedHandler = 403
- everything else rethrown
- sits before AuthorizationFilter
basics
~20 sIt's a filter that catches two security exceptions thrown further down the chain — AuthenticationException (not logged in) and AccessDeniedException (logged in but not allowed) — and turns them into an HTTP response instead of an error page.
solid answer
~40 sExceptionTranslationFilter sits near the end of the Spring Security filter chain and wraps the filters after it in a try/catch. It only reacts to two exceptions: AuthenticationException (the user isn't authenticated) and AccessDeniedException (the user is authenticated but lacks permission). For an AuthenticationException it kicks off authentication by calling the configured AuthenticationEntryPoint (e.g. redirect to /login or send 401). For an AccessDeniedException from a real user it hands off to the AccessDeniedHandler (403). Any other exception it simply rethrows. Its purpose is to translate Java security exceptions into a meaningful HTTP response — a login prompt or a forbidden result — rather than letting them bubble up as a 500 error.
code
java · 20 lines// Conceptually what ExceptionTranslationFilter.doFilter does:
try {
chain.doFilter(request, response); // AuthorizationFilter runs downstream
} catch (IOException ex) {
throw ex;
} catch (Exception ex) {
// Unwrap the cause chain looking for the two security exceptions
AuthenticationException authEx =
throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
AccessDeniedException accessEx =
throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
if (authEx != null) {
sendStartAuthentication(request, response, chain, authEx); // -> entryPoint.commence
} else if (accessEx != null) {
handleAccessDeniedException(request, response, chain, accessEx); // entryPoint OR handler
} else {
rethrow(ex); // not a security exception -> propagate (500)
}
}go deeper
Know the one-line purpose: catches auth/access-denied exceptions and turns them into a login prompt or 403.
Distinguish the two exceptions and the two responses (entry point vs access-denied handler); know it only wraps downstream filters.
Explain placement before AuthorizationFilter, the rethrow of non-security exceptions, and that it doesn't handle login-filter failures.
Frame it as the boundary where domain security exceptions become HTTP protocol responses, and reason about ordering guarantees it depends on.
## What it is `ExceptionTranslationFilter` is one of the built-in filters in Spring Security's filter chain (`SecurityFilterChain`). A *filter chain* is an ordered list of servlet filters that every HTTP request passes through before reaching your controller. Each filter can do work before and after the rest of the chain runs. `ExceptionTranslationFilter`'s single responsibility is **error translation**: it converts two specific Java exceptions into an appropriate HTTP outcome. It does **not** make authorization decisions itself. ## How it works mechanically It wraps the *downstream* part of the chain in a try/catch: ``` try { chain.doFilter(request, response); // run the rest of the chain } catch (Exception ex) { // look for AuthenticationException or AccessDeniedException inside ex } ``` Because it only wraps filters that come **after** it, it can only handle exceptions thrown downstream. In modern Spring Security 6 the filter that actually throws `AccessDeniedException` is `AuthorizationFilter` (it was `FilterSecurityInterceptor` in older versions), which is placed *after* `ExceptionTranslationFilter` on purpose. The two exceptions it recognizes: - **`AuthenticationException`** — the principal is not authenticated (anonymous, or credentials were rejected downstream). Response: start authentication via `AuthenticationEntryPoint.commence(...)`. Typical results: a `302` redirect to a login page, or a `401 Unauthorized`. - **`AccessDeniedException`** — the principal *is* authenticated but is not permitted. Response: for a fully authenticated user, delegate to `AccessDeniedHandler` (usually a `403 Forbidden`). Anything that is **not** one of these two (or doesn't unwrap to one of them) is **rethrown** unchanged, so it becomes a normal servlet error (often a `500`). ## Why it matters Without this filter, a security exception thrown deep in the chain would surface as an unhandled servlet error. `ExceptionTranslationFilter` is what makes the difference between a user seeing a login screen and seeing a stack trace. ## Key terms - **`AuthenticationEntryPoint`** — a strategy object that *commences* (starts) the authentication process. Called on `AuthenticationException`. - **`AccessDeniedHandler`** — a strategy object that decides what to do when an authenticated user is forbidden. Called on `AccessDeniedException` for real users. ## Gotcha It does **not** handle failures from authentication filters like `UsernamePasswordAuthenticationFilter` — those handle their own success/failure via `AuthenticationSuccessHandler`/`AuthenticationFailureHandler`. `ExceptionTranslationFilter` mostly reacts to the authorization step at the end of the chain.
- Which downstream filter typically throws the AccessDeniedException that this filter catches?AuthorizationFilter in Spring Security 6 (formerly FilterSecurityInterceptor). It is placed after ExceptionTranslationFilter so the try/catch can wrap it.
- What happens to an exception that is neither AuthenticationException nor AccessDeniedException?It is rethrown unchanged and propagates as a normal servlet error, typically surfacing as a 500 handled elsewhere.
saying these in an interview costs you the question
- Claiming it catches every exception in the chain (it only handles the two security exceptions)
- Saying it handles login-form authentication failures (those go through AuthenticationFailureHandler)
- Confusing it with a filter that makes authorization decisions — it only translates exceptions