skip to content

ExceptionTranslationFilter & EntryPoint

ExceptionTranslationFilter catches security exceptions and decides between starting authentication through an entry point and reporting access denied. It is what determines whether a request gets a 401 or a 403 — a question people answer wrongly all the time.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is the ExceptionTranslationFilter and what job does it do in the Spring Security filter chain?

level: juniorimportance: must knowfreq 55%

answer

  1. try/catch around downstream chain
  2. only AuthenticationException + AccessDeniedException
  3. EntryPoint = start auth; AccessDeniedHandler = 403
  4. everything else rethrown
  5. sits before AuthorizationFilter

basics

~20 s

It'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 s

ExceptionTranslationFilter 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
java
// 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

for a junior

Know the one-line purpose: catches auth/access-denied exceptions and turns them into a login prompt or 403.

for a middle

Distinguish the two exceptions and the two responses (entry point vs access-denied handler); know it only wraps downstream filters.

for a senior

Explain placement before AuthorizationFilter, the rethrow of non-security exceptions, and that it doesn't handle login-filter failures.

for a principal

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

context

open as a page

What is an AuthenticationEntryPoint, and how does it differ between a browser app and a REST API?

level: middleimportance: must knowfreq 60%

basics

~10 s

An AuthenticationEntryPoint decides how to ask an unauthenticated user to log in. A browser app usually redirects to a login page (302); a REST API usually returns 401 Unauthorized instead of redirecting.

open as a page

When an AccessDeniedException is thrown, how does ExceptionTranslationFilter decide between commencing the AuthenticationEntryPoint and delegating to the AccessDeniedHandler?

level: seniorimportance: must knowfreq 50%

basics

~20 s

It checks the current authentication. If the user is only anonymous or remembered (remember-me), it treats the denial as 'not really logged in' and calls the AuthenticationEntryPoint (prompt to log in). If the user is fully authenticated, it delegates to the AccessDeniedHandler (403).

open as a page

Where does ExceptionTranslationFilter sit relative to AuthorizationFilter, and why does its position matter?

level: seniorimportance: should knowfreq 35%

basics

~20 s

ExceptionTranslationFilter is placed just before AuthorizationFilter. Because it only wraps the filters after it in a try/catch, the authorization filter's AccessDeniedException is thrown downstream and caught by it. If it came after, it couldn't catch that exception.

open as a page

How does ExceptionTranslationFilter enable 'redirect back to the originally requested page after login', and how would you tune this in a mixed API/browser system?

level: principalimportance: should knowfreq 25%

basics

~20 s

Before commencing the entry point, ExceptionTranslationFilter saves the current request in a RequestCache. After the user logs in, a SavedRequestAware success handler pulls that saved request out and redirects them back to where they were originally going.

open as a page