title: How can I get Spring-Security to return a 401 response as a JSON format?
body: <p>I have a ReST API to an application with all controllers found under <code>/api/</code>, these all return JSON responses with a <code>@ControllerAdvice</code> which handles all exceptions to map to JSON formatted results.</p>
  
  <p>This works great as of spring 4.0 <code>@ControllerAdvice</code> now supports matching on annotations. What I can't work out is how to return a JSON result for a 401 - Unauthenticated and 400 - Bad Request responses.</p>
  
  <p>Instead Spring is simply returning the response to the container (tomcat) which renders this as HTML. How can I intercept this and render a JSON result using the same technique that my <code>@ControllerAdvice</code> is using.</p>
  
  <p><strong>security.xml</strong></p>
  
  <pre class="lang-xml prettyprint-override"><code>&lt;bean id="xBasicAuthenticationEntryPoint"
        class="com.example.security.XBasicAuthenticationEntryPoint"&gt;
    &lt;property name="realmName" value="com.example.unite"/&gt;
  &lt;/bean&gt;
  &lt;security:http pattern="/api/**"
                 create-session="never"
                 use-expressions="true"&gt;
    &lt;security:http-basic entry-point-ref="xBasicAuthenticationEntryPoint"/&gt;
    &lt;security:session-management /&gt;
    &lt;security:intercept-url pattern="/api/**" access="isAuthenticated()"/&gt;
  &lt;/security:http&gt;
  </code></pre>
  
  <p><strong>XBasicAuthenticationEntryPoint</strong></p>
  
  <pre><code>public class XBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
      @Override
      public void commence(HttpServletRequest request,
                           HttpServletResponse response,
                           AuthenticationException authException)
              throws IOException, ServletException {
          HttpServletResponse httpResponse = (HttpServletResponse) response;
          httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                                 authException.getMessage());
      }
  }
  </code></pre>
  
  <p>I can solve 401 by using the <code>BasicAuthenticationEntryPoint</code> to write directly to the output stream, but I'm not sure it's the best approach.</p>
  
  <pre><code>public class XBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
  
      private final ObjectMapper om;
  
      @Autowired
      public XBasicAuthenticationEntryPoint(ObjectMapper om) {
          this.om = om;
      }
  
      @Override
      public void commence(HttpServletRequest request,
                           HttpServletResponse response,
                           AuthenticationException authException)
              throws IOException, ServletException {
          HttpServletResponse httpResponse = (HttpServletResponse) response;
          httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
          om.writeValue(httpResponse.getOutputStream(),
                        new ApiError(request.getRequestURI(),
                        HttpStatus.SC_UNAUTHORIZED,
                        "You must sign in or provide basic authentication."));
      }
  
  }
  </code></pre>
  
  <p>I am yet to figure out how to handle 400 though, I once tried a catch all controller which did work, but it seemed that sometimes it would have odd conflicting behaviour with other controllers that I don't want to revisit.</p>
  
  <p>My <code>ControllerAdvice</code> implementation has a catch all which if spring throws any exception for bad request (400) it should in theory capture it, but it does not:</p>
  
  <pre><code>@ControllerAdvice(annotations = {RestController.class})
  public class ApiControllerAdvisor {
      @ExceptionHandler(Throwable.class)
      public ResponseEntity&lt;ApiError&gt; exception(Throwable exception,
                                                WebRequest request,
                                                HttpServletRequest req) {
          ApiError err = new ApiError(req.getRequestURI(), exception);
          return new ResponseEntity&lt;&gt;(err, err.getStatus());
      }
  }
  </code></pre>