How to logout oauth2 client in Spring?

gstackoverflow picture gstackoverflow · May 15, 2018 · Viewed 11.6k times · Source

I have the simplest oauth2 client:

@EnableAutoConfiguration
@Configuration
@EnableOAuth2Sso
@RestController
public class ClientApplication {

    @RequestMapping("/")
    public String home(Principal user, HttpServletRequest request, HttpServletResponse response) throws ServletException {       
        return "Hello " + user.getName();
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(ClientApplication.class)
                .properties("spring.config.name=application").run(args);
    }

}

I also have the following application.yml:

server:
  port: 9999
  servlet:
    context-path: /client
security:
  oauth2:
    client:
      client-id: acme
      client-secret: acmesecret
      access-token-uri: http://localhost:8080/oauth/token
      user-authorization-uri: http://localhost:8080/oauth/authorize
    resource:
      user-info-uri: http://localhost:8080/me

logging:
  level:
    org.springframework.security: DEBUG
    org.springframework.web: DEBUG

It is the full code. I don't have any additional source code. It works properly.

But now I want to add a logout feature. I've added an endpoint but it doesn't work. I tried to do the following:

@RequestMapping("/logout")
    public void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        authentication.setAuthenticated(false);
        new SecurityContextLogoutHandler().logout(request,response,authentication);
        SecurityContextHolder.clearContext();
        request.logout();
        request.getSession().invalidate();
    }

But I am still logged in and can access / url and it responds to me with the username.

Can you help me fix this issue?

Update

I tried the approach described here https://spring.io/guides/tutorials/spring-boot-oauth2/#_social_login_logout :

@EnableAutoConfiguration
@Configuration
@EnableOAuth2Sso
@Controller
public class ClientApplication extends WebSecurityConfigurerAdapter {
    private Logger logger = LoggerFactory.getLogger(ClientApplication.class);

    @RequestMapping("/hello")
    public String home(Principal user, HttpServletRequest request, HttpServletResponse response, Model model) throws ServletException {
        model.addAttribute("name", user.getName());
        return "hello";
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.antMatcher("/**")
                .authorizeRequests()
                .antMatchers( "/login**", "/webjars/**", "/error**").permitAll()
                .anyRequest()
                .authenticated()
                .and().logout().logoutSuccessUrl("/").permitAll()
                .and()
                    .csrf()
                    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
        // @formatter:on
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(ClientApplication.class)
                .properties("spring.config.name=application").run(args);
    }
}

and on FE I wrote:

<script type="text/javascript">
        $.ajaxSetup({
            beforeSend: function (xhr, settings) {
                if (settings.type == 'POST' || settings.type == 'PUT'
                    || settings.type == 'DELETE') {
                    if (!(/^http:.*/.test(settings.url) || /^https:.*/
                            .test(settings.url))) {
                        // Only send the token to relative URLs i.e. locally.
                        xhr.setRequestHeader("X-XSRF-TOKEN",
                            Cookies.get('XSRF-TOKEN'));
                    }
                }
            }
        });
        var logout = function () {
            $.post("/client/logout", function () {
                $("#user").html('');
                $(".unauthenticated").show();
                $(".authenticated").hide();
            });
            return true;
        };
        $(function() {
            $("#logoutButton").on("click", function () {
                logout();
            });
        });

    </script>

and

<input type="button" id="logoutButton" value="Logout"/>

But it still doesn't work. It results in the following behavior:

Post http://localhost:9999/client/logout redirects to the http://localhost:9999/client but this page doesn't exist

source code on gitub:
client - https://github.com/gredwhite/logour_social-auth-client (use localhost:9999/client/hello url)
server - https://github.com/gredwhite/logout_social-auth-server

Answer

Dharita Chokshi picture Dharita Chokshi · May 24, 2018

Add following code snippet to your ClientApplication class. This will also clear your session details.

Replace below code with the configure method of your web security adapter class.

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**")
                .authorizeRequests()
                .antMatchers( "/login**", "/webjars/**", "/error**").permitAll()
                .anyRequest()
                .authenticated()
                .and().logout().invalidateHttpSession(true)
                .clearAuthentication(true).logoutSuccessUrl("/login?logout").deleteCookies("JSESSIONID").permitAll().and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }