Logout in an OAuth Secured Application

1. Overview

In this quick tutorial, we’re going to show how we can add logout functionality to an OAuth Spring Security application.

We will, of course, use the OAuth application described in a previous article – Creating a REST API with OAuth2.

Note: this article is using the Spring OAuth legacy project. For the version of this article using the new Spring Security 5 stack, have a look at our article Logout in an OAuth Secured Application.

2. Remove the Access Token

Simply put, logging out in an OAuth-secured environment involves rendering the user’s Access Token invalid – so it can no longer be used.

In a JdbcTokenStore-based implementation, this means removing the token from the TokenStore.

Let’s implement a delete operation for the token. We’re going to use the parimary /oauth/token URL structure here and simply introduce a new DELETE operation for it.

Now, because we’re actually using the /oauth/token URI here – we need to handle it carefully. We won’t be able to simply add this to any controller – because the framework already has operations mapped to that URI – with POST and GET.

Instead what we need to do is to define this is a @FrameworkEndpoint – so that it gets picked up and resolved by the FrameworkEndpointHandlerMapping instead of the standard RequestMappingHandlerMapping. That way we won’t run into any partial matches and we won’t have any conflicts:

@FrameworkEndpoint
public class RevokeTokenEndpoint {

    @Resource(name = "tokenServices")
    ConsumerTokenServices tokenServices;

    @RequestMapping(method = RequestMethod.DELETE, value = "/oauth/token")
    @ResponseBody
    public void revokeToken(HttpServletRequest request) {
        String authorization = request.getHeader("Authorization");
        if (authorization != null && authorization.contains("Bearer")){
            String tokenId = authorization.substring("Bearer".length()+1);
            tokenServices.revokeToken(tokenId);
        }
    }
}

Notice how we’re extracting the token out of the request, simply using the standard Authorization header.

3. Remove the Refresh Token

In a previous article on Handling the Refresh Token, we have set up our application to be able to refresh the Access Token, using a Refresh Token. This implementation makes use of a Zuul proxy – with a CustomPostZuulFilter to add the refresh_token value received from the Authorization Server to a refreshToken cookie.

When revoking the Access Token, as shown in the previous section, the Refresh Token associated with it is also invalidated. However, the httpOnly cookie will remain set on the client, given that we can’t remove it via JavaScript – so we need to remove it from the server side.

Let’s enhance the CustomPostZuulFilter implementation that intercepts the /oauth/token/revoke URL so that it will remove the refreshToken cookie when encountering this URL:

@Component
public class CustomPostZuulFilter extends ZuulFilter {
    //...
    @Override
    public Object run() {
        //...
        String requestMethod = ctx.getRequest().getMethod();
        if (requestURI.contains("oauth/token") && requestMethod.equals("DELETE")) {
            Cookie cookie = new Cookie("refreshToken", "");
            cookie.setMaxAge(0);
            cookie.setPath(ctx.getRequest().getContextPath() + "/oauth/token");
            ctx.getResponse().addCookie(cookie);
        }
        //...
    }
}

4. Remove the Access Token from the AngularJS Client

Besides revoking the access token from the token store, the access_token cookie will also need to be removed from the client side.

Let’s add a method to our AngularJS controller that clears the access_token cookie and calls the /oauth/token/revoke DELETE mapping:

$scope.logout = function() {
    logout($scope.loginData);
}
function logout(params) {
    var req = {
        method: 'DELETE',
        url: "oauth/token"
    }
    $http(req).then(
        function(data){
            $cookies.remove("access_token");
            window.location.href="login";
        },function(){
            console.log("error");
        }
    );
}

This function will be called when clicking on the Logout link:

<a class="btn btn-info" href="#" ng-click="logout()">Logout</a>

5. Conclusion

In this quick but in-depth tutorial, we’ve shown how we can logout a user from an OAuth secured application and invalidate the tokens of that user.

The full source code of the examples can be found over on GitHub.

Related posts:

Deploy a Spring Boot WAR into a Tomcat Server
Java Program to Implement Variable length array
Luồng Daemon (Daemon Thread) trong Java
Guide to Dynamic Tests in Junit 5
Java Program to Implement Depth-limited Search
Java Program to Implement Randomized Binary Search Tree
Java Program to Find Location of a Point Placed in Three Dimensions Using K-D Trees
Simplify the DAO with Spring and Java Generics
Vector trong Java
How to Return 404 with Spring WebFlux
Guide To CompletableFuture
Java Program to Implement Gaussian Elimination Algorithm
Java Program to Check Cycle in a Graph using Graph traversal
Java Program to Find the Shortest Path from Source Vertex to All Other Vertices in Linear Time
Java Program to Implement Attribute API
TreeSet và sử dụng Comparable, Comparator trong java
Java Program to Implement Double Ended Queue
Java Program to Implement Tarjan Algorithm
Java Program to Implement the Binary Counting Method to Generate Subsets of a Set
Working with Kotlin and JPA
Hướng dẫn Java Design Pattern – Adapter
Java Program to Represent Graph Using 2D Arrays
Tính đóng gói (Encapsulation) trong java
@Lookup Annotation in Spring
Introduction to Java Serialization
Java – Create a File
A Guide to WatchService in Java NIO2
Java Program to Implement ConcurrentLinkedQueue API
Java Program to Use Boruvka’s Algorithm to Find the Minimum Spanning Tree
Java Program to Implement Floyd-Warshall Algorithm
Giới thiệu về Stream API trong Java 8
Java Program to Find Whether a Path Exists Between 2 Given Nodes