Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

With Spring Boot 1.5.6.RELEASE I was able to send HTTP Status code 401 instead of 403 as described in How let spring security response unauthorized(http 401 code) if requesting uri without authentication , by doing this:

public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //...
        http.exceptionHandling()
                .authenticationEntryPoint(new Http401AuthenticationEntryPoint("myHeader"));
        //...

using the org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint class.

I just upgraded to Spring Boot 2.0.0.RELEASE and found there is not such class any more (at least in that package).

Questions:

  • Does this class (Http401AuthenticationEntryPoint) exist yet in Spring Boot?

  • If no, what could be a good alternative for keeping the same behavior in an existing project in order to keep consistency with other implementations which depend on this status code (401) instead of 403?

    Please notice this is different from Spring Security anonymous 401 instead of 403 because it's referring specifically to SpringBoot 2 (there are solutions in that post not applicable anymore in SpringBoot version 2 or others are not needed at all)

    @Leponzo, thanks for pointing this out. I think it shouldn't be considered a duplicate and added a comment on the original post explaining why -- for future readers. I did find an answer (stackoverflow.com/a/52986942/5640649) very similar to the one I posted below -- but it was actually posted after mine :) ... anyways, in a broader scope, I think they're different questions. – lealceldeiro Mar 1, 2022 at 13:05

    Heads up

    By default Spring Boot 2 will return 401 when spring-boot-starter-security is added as a dependency and an unauthorized request is performed.

    This may change if you place some custom configurations to modify the security mechanism behavior. If that's the case and you truly need to force the 401 status, then read the below original post.

    Original Post

    The class org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint was removed in favor of org.springframework.security.web.authentication.HttpStatusEntryPoint.

    In my case the code would go like this:

    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //...
            http.exceptionHandling()
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
            //...
    

    Bonus

    If you need to return some information in the response body or customize the response somehow you can do something like this:

    1- Extend AuthenticationEntryPoint

    public class MyEntryPoint implements AuthenticationEntryPoint {
        private final HttpStatus httpStatus;
        private final Object responseBody;
        public MyEntryPoint(HttpStatus httpStatus, Object responseBody) {
            Assert.notNull(httpStatus, "httpStatus cannot be null");
            Assert.notNull(responseBody, "responseBody cannot be null");
            this.httpStatus = httpStatus;
            this.responseBody = responseBody;
        @Override
        public final void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
            response.setStatus(httpStatus.value());
            try (PrintWriter writer = response.getWriter()) {
                writer.print(new ObjectMapper().writeValueAsString(responseBody));
    

    2- Provide an instance of MyEntryPoint to the security configuration

    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // customize your response body as needed
            Map<String, String> responseBody = new HashMap<>();
            responseBody.put("error", "unauthorized");
            //...
            http.exceptionHandling()
                .authenticationEntryPoint(new MyEntryPoint(HttpStatus.UNAUTHORIZED, responseBody));
            //...
                    Now bad credential requests are returning 401, but empty-body response. Also, unauthorized requests, which should return 403, are also returning 401 with empty-body response.
    – Nelio Alves
                    Mar 26, 2018 at 17:49
                    This returns 401s with no body. That's fine for js, but when viewed in Firefox it's a blank page and when viewed in Chrome it says "This page isn't working". It's easy to make your own replacement of the Htp401AuthenticationEntryPoint though and use that. Just implement AuthenticationEntryPoint and set whatever status and message you want.
    – Planky
                    Dec 30, 2019 at 22:20
                    @Planky thank you very much for pointing that out! I just put a possible approach others might follow based on your comment :)
    – lealceldeiro
                    Apr 10, 2020 at 9:31
    

    Just to elaborate @lealceldeiro's answer:

    Before Spring Boot 2 my Securiy Configuration class looked like this:

    @Configuration
    public class MyConfig extends WebSecurityConfigurerAdapter {
        @Bean
        public Http401AuthenticationEntryPoint securityException401EntryPoint() {
          return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\"");
        @Autowired
        private Http401AuthenticationEntryPoint authEntrypoint;
        @Override
        protected void configure(HttpSecurity http) throws Exception {
          // some http configuration ...
          // Spring Boot 1.5.x style
          http.exceptionHandling().authenticationEntryPoint(authEntrypoint);
    //...
    

    And now in Spring Boot 2 it looks like this:

    @Configuration
    public class MyConfig extends WebSecurityConfigurerAdapter {
        //Bean configuration for Http401AuthenticationEntryPoint can be removed
        //Autowiring also removed
        @Override
        protected void configure(HttpSecurity http) throws Exception {
          // some http configuration ...
          // Spring Boot 2 style
          http.exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
    //...
    

    See also this comment in Spring Boot Github Repo > PR Remove Http401AuthenticationEntryPoint.

    The solution looks nice and clean, but it is missing the mandatory WWW-Authenticate Header, which would tell the client how he can attempt to authenticate – dube Dec 2, 2020 at 8:01

    Http401AuthenticationEntryPoint was removed.

    See Spring Boot Github Repo > Issue #10715 (Remove Http401AuthenticationEntryPoint):

    Remove Http401AuthenticationEntryPoint

    rwinch commented on 20 Oct 2017
    As far as I can tell it is not being used in the Spring Boot code base, so it might be good to remove Http401AuthenticationEntryPoint.

    Depending on your requirements, you could use:

  • HttpStatusEntryPoint
  • BasicAuthenticationEntryPoint
  • Thanks, very useful link from spring boot git repo. In the answer I provided future readers can see how I used HttpStatusEntryPoint according to my requirements. – lealceldeiro Oct 17, 2018 at 14:59

    For reactive (WebFlux) stack you can override the returned status code by adding such @Bean to catch some specific exceptions:

    @Component
    class MyErrorAttributes : DefaultErrorAttributes() {
    override fun getErrorAttributes(
        request: ServerRequest,
        options: ErrorAttributeOptions
    ): MutableMap<String, Any> {
        val cause = super.getError(request)
        val errorAttributes = super.getErrorAttributes(request, options)
        when (cause) {
            is TokenExpiredException -> {
                errorAttributes["status"] = HttpStatus.UNAUTHORIZED.value()
                errorAttributes["error"] = HttpStatus.UNAUTHORIZED.reasonPhrase
        return errorAttributes
    

    You can customize your logic with overriding the class AuthenticationEntryPoint this should be working:

    @Component public class AuthEntryPointException implements AuthenticationEntryPoint, Serializable {
        private static final long serialVersionUID = -8970718410437077606L;
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException {
            response.setStatus(HttpStatus.SC_UNAUTHORIZED);
            response.setContentType("application/json");
            response.getWriter().write("{\"result\":\"UNAUTHORIZED\",\"message\":\"UNAUTHORIZED or Invalid Token\"}");
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.

  •