Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to logout oauth2 client in Spring?

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

like image 903
gstackoverflow Avatar asked May 15 '18 16:05

gstackoverflow


People also ask

How does OAuth2 logout work?

GET /oauth/login/logout. Destroys any authentication cookies associated with the current OAuth session. Once the API calls are made, the logout API removes the OAuthToken cookie and forces users to log in again before invoking any protected API calls.


1 Answers

You can delete the refresh token as well as access token from database to save space.

@PostMapping("/oauth/logout")
public ResponseEntity<String> revoke(HttpServletRequest request) {
    try {
        String authorization = request.getHeader("Authorization");
        if (authorization != null && authorization.contains("Bearer")) {
            String tokenValue = authorization.replace("Bearer", "").trim();

            OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
            tokenStore.removeAccessToken(accessToken);

            //OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(tokenValue);
            OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
            tokenStore.removeRefreshToken(refreshToken);
        }
    } catch (Exception e) {
        return ResponseEntity.badRequest().body("Invalid access token");
    }

    return ResponseEntity.ok().body("Access token invalidated successfully");
}

The URL to logout will be : http://localhost:9999/oauth/logout Also, pass the access token in the Authorization header, as

Authorization: Bearer 0cb72897-c4f7-4f01-aed9-2f3f79a75484

where, 0cb72897-c4f7-4f01-aed9-2f3f79a75484 is the access token.

Since, its Spring security, don't forget to bypass /oauth/logout url from authorize access, as

public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/hello", "/oauth/logout");
}

Hope, it will solve your logout problem in Springboot2+Oauth2. Its working for me.

like image 196
Dharmender Rawat Avatar answered Sep 18 '22 18:09

Dharmender Rawat