Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

OAuth 2.0 Token Management With Stormpath and Spring Boot

DZone's Guide to

OAuth 2.0 Token Management With Stormpath and Spring Boot

OAuth2 token management is often misunderstood and difficult to implement correctly. Fortunately, with Stormpath’s SDKs and integrations, we make Token Management easy. This 20-minute tutorial will show you how to implement Token Management with Stormpath’s Spring Boot and Spring Security integrations.

· Java Zone
Free Resource

Learn how our document data model can map directly to how you program your app, and native database features like secondary indexes, geospatial and text search give you full access to your data. Brought to you in partnership with MongoDB.

OAuth2 token management is often misunderstood and difficult to implement correctly. Fortunately, with Stormpath’s SDKs and integrations, we make Token Management easy—fun, even. This 20-minute tutorial will show you how to implement Token Management with Stormpath’s Spring Boot and Spring Security integrations.

While Spring Security does have built in OAuth2 support, there is no native token management support in Spring Boot, and working with the OAuth 2.0 protocol has been known to cause spontaneous outbreaks of hives, cold sweats, and prolonged “face desking”.

face_desk

Stormpath’s Spring Boot integration supports two OAuth flows: grant_type=password and grant_type=refresh_token. The Password Grant Type allows you to pass in a username and password and get back an Access Token and a Refresh Token. The Refresh Token Grant Type allows you to pass in a Refresh Token and get back a new Access Token.

They are both accessed through a single endpoint, /oauth/token, which is available out of the box with the Stormpath integration. So, fear not! Stormpath’s Token Management does all the heavy lifting. You just have to create the HTTP request using some basic rules discussed below.

Resources for This Tutorial

By then end of this post, you’ll have everything you need to swap a username and password for a set of tokens that allows a user to access restricted resources in an application. You’ll also be able to refresh and revoke tokens to provide a fine degree of control over how users access your application and how long they stay logged in.

The code that backs this post is here.

You can see the example in action at: https://jquery-spa.herokuapp.com (due to the Heroku sleep policy, you may have to wait a few seconds for the app to respond initially) and you can deploy it to your Heroku account right now using the button below.

Deploy

While Token Management is typically a behind-the-scenes affair, this example uses a SPA or Single Page Application. To keep the example simple (and JavaScript framework agnostic), all calls are made using jQuery’s ajax functionality.

Modern Token Management – Access And Refresh Tokens

In a modern application that supports OAuth2 Token Management, a user’s session typically has one Access Token with a short expiration and one Refresh Token with a longer expiration. When the Access Token expires, the application will use the Refresh Token to obtain a new Access Token. This process is repeated until the Refresh Token expires. At this point, the user would need to log into the application again.

For a deep dive into OAuth tokens and how they work, check out my colleague Randall’s post that explores OAuth in detail.

JSON Web Token (JWT) Security PSA

The OAuth2 specification does not specify a particular token format, so Stormpath uses JWTs to represent Access Tokens and Refresh Tokens. JWTs have additional information encoded into them, and more importantly, they are cryptographically signed to provide conclusive evidence that the token has not been tampered with.

Stormpath Access Tokens also provide an important layer of additional security – they always contain a reference to the associated Refresh Token. This reference is a claim identified by the code rti. It’s one of the ways Stormpath ensures it is an Access Token being used to access a protected resource and not a Refresh Token. Other implementations of OAuth2 have (inadvertently) allowed a refresh token to act as an access token, giving users longer access then they should have. We guard against that.

If you want to learn more about JWTs and how to use them securely, check out our posts on how to Use JWTs the Right Way, Build Secure User Interfaces with JWTs, and Where to Store Your JWTs.

OK, with all that out of the way, let's get started!

Spring Security Configuration

In the sections that follow, we’re going to explore the example application through the lens of the jQuery calls that are made to the backend /oauth/token endpoint in the Spring Boot App.

Before we get to that, let’s look at the Spring Security configuration for this example application:

@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.apply(stormpath()).and()
            .authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/decode").permitAll()
            .antMatchers("/static/**").permitAll();
    }
}


In the above configuration, we are allowing unauthenticated access to / and /decode as well as any path within /static. We’ll see this in action as we work through the example below.

Let’s Get Some Tokens

There are two primary static files in our SPA example: home.html and static/js/token-management-guided-tour.js.

home.html is a Thymeleaf template in which the static/js/token-management-guided-tour.js JavaScript file is loaded.

Here’s a view of the different sections of home.html:

home

It’s broken down into 7 steps and the application walks you through the example, “guided tour” style.

The first step is to pass in an email and password and get back Access and Refresh Tokens. Let’s look at that in action.

Login With Email and Password

Here’s the jQuery code that processes the initial request to the /oauth/token endpoint (error and complete functions omitted for brevity):

$('#login-form').submit(function (e) {

    var theForm = $('#login-form');

    $.ajax({
        type: 'post',
        url: '/oauth/token',
        data: theForm.serialize(),
        success: function (data) {
            accessToken = data.access_token;
            refreshToken = data.refresh_token;
            var accessTokenParts = accessToken.split('.');
            $.each(['header', 'payload', 'signature'], function (index, value) {
                $('#access-token-' + value).html(accessTokenParts[index]);
            });
            $('#login-error').hide();
            showOnlyDiv('access-token-div');
        }
    });

    e.preventDefault();
});


Line 3 gives us a handle to the form.

Per the OAuth2 spec, the method will be POST and the Content-Type is application/x-www-form-urlencoded (this is the default for jQuery’s $.ajax call). The data passed to /oauth/token will look like this:

grant_type=password&username=<usernam>&password=<password>


This is the result of the call to theForm.serialize() on line 8.

The success handler which begins on line 9 stores the access_token and the refresh_token in local variables. It also displays the parts of the access_token (header, payload, and signature) in your browser so you can see visually what the JWT looks like:

access_token

Note: As the screenshot shows, the example app is for demonstration purposes only. In “real life” you would not want to show an Access Token in the browser and you would want to use best practices for storing tokens in your client app. We have a great post on those best practices here.

Anatomy of a Stormpath Access Token

In the example app, if you click on the Decode button, you will see something like the following:

decoded

This shows you the header and the payload sections of the JWT that is the Access Token. To understand how we decoded our Access Token, we need to take a look at the decode method in the APIController in the example app:

@RequestMapping("/decode")
public Jws<Claims> decode(@RequestParam String token) throws UnsupportedEncodingException {

    Jws<Claims> claims = Jwts.parser()
        .setSigningKey(client.getApiKey().getSecret().getBytes("UTF-8"))
        .parseClaimsJws(token);

    return claims;
}


Finally, the method returns the Jws<Claims> object. This is where Spring Boot’s automatic Jackson JSON mapper kicks in and converts that object to JSON. Here’s what the raw response looks like:

{
    "header": {
        "kid": "R92SBHJC1U4DAIMGQ3MHOGVMX",
        "alg": "HS256"
    },
    "body": {
        "jti": "6UBPQ975cDDiz8ckHqWIZF",
        "iat": 1456242057,
        "iss": "https://api.stormpath.com/v1/applications/2nBCvauLgETX8wO0VvS9mQ",
        "sub": "https://api.stormpath.com/v1/accounts/49CK1VvY2jQwUBH7UnP5zC",
        "exp": 1456245657,
        "rti": "6UBPQ5n0hcukMJWt5af1xB"
    },
    "signature": "Pm30FjdXOmx_fMGhfku85Z9xc6qE-EZgKHI4mV46KO8"
}


Notice that the body (payload) of the decoded JWT includes a reference to the Stormpath Account in the sub (subject) claim. It is this Account that is used when accessing restricted resources as we will see next.

Using an Access Token

After decoding the Access Token, the next step in our example app’s guided tour is to hit a restricted resource using that Access Token. Here’s the jQuery code that accomplishes that:

$('#restricted').click(function () {

    $('#account-info-table tbody').empty();
    $.ajax({
        type: 'get',
        url: '/restricted',
        success: function (data) {
            var newRowContent = '<tr><td>' + data.fullName + '</td><td>' + data.email + '</td></tr>';
            $('#account-info-table tbody').append(newRowContent);
            showOnlyDiv('account-info-div');
        }
    })
});


The jQuery success function above displays the Account information returned from the request to /restricted.

Token Management: It’s Refreshing!

The next step in our journey is to use the Refresh Token to obtain a new Access Token. In a typical mobile application, the following would happen behind the scenes without the user ever knowing:

  1. The current Access Token expires
  2. The user tries to access a restricted part of the application using the (expired) Access Token
  3. The application receives a 401 (unauthorized) HTTP response code
  4. The application uses the Refresh Token to obtain a new Access Token
  5. The application tries to access the restricted part of the application using the new Access Token
  6. The user sees the result of that request without having to log in again

Note: If the Refresh Token has expired, then the user of the application would need to log in again at Step 4

Stormpath provides an OAuth Policy in the admin console to set expirations for Access Tokens and Refresh Tokens.

A Look at the OAuth Policy

Here’s what the OAuth Policy looks like in the Stormpath Admin Console:

oauth policy

The default time-to-live for Access Tokens is 1 hour and the default TTL for Refresh Tokens is 60 days.

Refreshing the Access Token

When you click the Refresh the Access Token button in the example app, you get a response that looks like this:

refresh

This displays the new Access Token retrieved in the refresh process. To understand what’s going on there, we turn back to our jQuery code (success handler omitted for brevity):

$('#refresh').click(function () {

    $.ajax({
        type: 'post',
        url: '/oauth/token',
        data: 'grant_type=refresh_token&refresh_token=' + refreshToken,
        success: function (data) {
        }
    })
});


The response from this ajax call is a new Access Token which is then displayed in the browser underneath the old Access Token.

Kick that Token to the Curb

The last part of our Token Management joyride is revoking the Access and Refresh tokens. This is accomplished by hitting the (built in) /logout endpoint providing the Access Token as a Bearer token as we did when hitting a restricted resource earlier. Let’s look at the jQuery code that accomplishes this:

$('#revoke').click(function () {

    $.ajax({
        type: 'post',
        url: '/logout',
        success: function () {
            showOnlyDiv('revoke-div');
        }
    })
});


The example app tries to hit the /restricted path using the (now deleted) Access Token. The result looks like this:

fail

The result shows that trying to use a deleted Access Token will not work.

In Summary

The /oauth/token endpoint provided out-of-the-box in Stormpath’s Spring Boot integration enables all the functionality of a modern Token Management system.

In this post, we’ve covered what Access and Refresh tokens are, as well as how they are obtained, used, refreshed and revoked.

You can see the example application used throughout this post at: https://jquery-spa.herokuapp.com or, you can use the button below to deploy the app to your own Heroku account.

Deploy

Feel free to drop a line over to email anytime, or hit me up on Twitter @afitnerd.

Like what you see? to keep up with the latest releases.

Discover when your data grows or your application performance demands increase, MongoDB Atlas allows you to scale out your deployment with an automated sharding process that ensures zero application downtime. Brought to you in partnership with MongoDB.

Topics:
access ,format ,refresh ,token ,spring boot ,native ,tokens

Published at DZone with permission of Micah Silverman, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}