Spring Boot 2 And OAuth 2 - User Authorization and Token Revocation

By Sebastian Feduniak | February 12, 2019

Spring Boot 2 And OAuth 2 - User Authorization and Token Revocation

More security!

In a modern application the authentication on its own is not sufficient. It’s a common practice to grant different privileges to a group of users. Also when we talk about users, the two basic uses cases come to our mind - user log-in and log-out. In this post we will cover user authorization and OAuth 2 token revocation in the Spring Boot 2 framework. This tutorial is a second part of the recent post introducing token-based authentication in the Spring framework. It’s recommended to start with it first.

The project is available on our Github repository here. I strongly encourage you to actually write the code rather than reading it! For your convenience, each of the steps has its own git tag so you can directly jump into the part that you are interested in. I will mention the tag name in every section but also project’s readme file summarizes all of the tags in one place.

Why do I need authorization?

You know Google Docs, aren’t you? You can share your documents in a way that some people can only read the document but another group of users can edit it. This is one of the examples of authorization.

Technically you can have different roles in your application and assign these roles to users. A role specifies which parts of the application are available for the users having this role assigned. So it makes your application even more secure.

In this post we will add an administrator resource which will allow to see the data that normal user cannot access.

Step 1: Administration panel

Git tag: roles-and-admin-panel.

Our goal is to create another endpoint to retrieve sensitive data. It will be accessible only for the admin users - users having ROLE_ADMIN assigned. As it might be helpful later, let’s allow administrators to list all the active authentication tokens.

The plan is as follows: we need users store where we can register people and assign them a suitable role. Then we need to configure authorization in the Spring framework. The last thing it to implement Admin resource and annotate it in way that only admin users can access it.

Let’s do it!

Users store

We will create a new table in the database to store the data. Let’s add the following changeset to the database migration:

We just keep email, password and the role. Keep in mind it’s just a sample application, you should never keep the credentials in plain text.

We also need a class representing this entity:

And a DAO able to retrieve the data from database:

Yeah, it’s just so easy! Thanks to built-in JPA support, you don’t need to write SQL command on your own.

In the next change-set I added one admin and one regular user. It’s just for testing. Normally you won’t register your users that way :)

Ok, we are done with the users!

Spring Security Configuration

Not so much to do here.

First enable authorization in the security config.

As you can see, the only one thing we modified is setting securedEnabled = true.

Then we need to modify our authentication provider a little bit because we need to read the users from the database.

The main difference is injecting user repository here, retrieving the user from the database and adding the role.

At this point we have fully working application with the difference that the users are kept in the database instead of memory.

Administration resource - the ugly way

It’s time to add new endpoint to the application which will allow to read all the active authentication tokens. Let’s assume the only thing we have for now is OAuth 2 database table. See its definition below.

We are interested in the token column which is byte data. But we can simply deserialize it to org.springframework.security.oauth2.common.DefaultOAuth2AccessToken and that way retrieve the token’s value.

So the new endpoint /token/list will return a list of the active tokens for all the users.

Secure endpoints

We are almost done with the authorization. The last and the simplest thing is to annotate the endpoints with a required role. An example you can see above, in the admin panel.

Notice @Secured({"ROLE_ADMIN"}) in the code. It means that ADMIN role is required to access this endpoint.

That’s it! It was the last piece when it comes to authorization!

Step 2: Testing

As you may notice, after the changes we are not able to build the project because of the failing tests. In this section I will show you how to check it manually. Then we will fix the automated tests.

Manual testing

First, request an authentication token for the regular user.

This should return a token.

Now, let’s try to access admin panel using the above.

You should see HTTP/1.1 403 error.

That works as expected. Regular user cannot access administration endpoint. Let’s repeat the above steps for the admin user.

Requesting token:

Token response:

Requesting a list of all active tokens:

You should see the list containing all of the tokens.

Great! So far, so good!

Automated tests

The tests are failing because the mock users don’t have required roles assigned. So let’s add another user that will be able to access the resources.

And then modify the test suite.

As you can see, we test that the user without any role cannot access the /api/hello endpoint but it’s available for the second user with the ROLE_USER role.

With this fixes we should be able to build the project.

Revocation - the missing part.

Sometimes you may want to invalidate the token. It might be helpful for the user log-out use case. In this section we will see how to implement it in the Spring Boot service.

Step 3: Authentication token revocation

Git tag: authentication-token-revocation.

Our goal is to create another endpoint that can be used to revoke authentication token. We want to minimize the implementation and use DefaultTokenServices which is already available in the Spring framework.

The plan is as follows: we need to create and register DefaultTokenServices bean and then create a new endpoint using it to revoke the token. Additionally, we will prettify the administration panel to get rid of reading the token from the database directly.

Let’s do it!

Registering DefaultTokenServices

We will create another configuration class that will be responsible for exposing two beans: * TokenStore - it’s already present but it we will move it to the new class to keep logically related beans together in one place * DefaultTokenServices - a new bean that can be used to manipulate a token

After that, we can inject the TokenStore in the AuthorizationServerConfig to avoid code duplication.

Token revocation endpoint

Now, let’s create another endpoint that will use the DefaultTokenServices to revoke the token.

Notice that we inject Authentication object here so this method is only available for the users that already have a valid token. It makes sense if you think about logging out function. What about the refresh token? It will be invalidated automatically so the only way to access the application again is to re-authenticate.

That’s it! Let’s give it a try!

Step 4: Testing

Authenticate both admin and regular users.

Admin

User

List all the tokens using admin token.

Call the test endpoint using user token.

Now, revoke the user token.

You should just receive OK response HTTP/1.1 200. Now, try to call the test endpoint again.

It should not be allowed.

List all tokens again.

And you can see that the user token is missing.

So finally let’s try to refresh the user token.

It should not be allowed.

Good job! It’s working!

Troubleshooting

Depending on the Spring Security library version, you may encounter the following error while trying to refresh the token.

And you should see something similar in the application log.

To solve it, just use UserDetailsService instead of AuthenticationProvider for the user authentication.

Just implement the required method:

And configure it in the Spring Security.

This should fix the issue.

Bonus: Administration resource - the pretty way

As a small addition, you can change the administration panel to retrieve tokens using DefaultTokenServices and get rid of token deserialization.

Much better! :)

Summary

In this tutorial we showed how easy it is to configure authorization in the Spring Boot framework. Also, we implemented token revocation using the integration with OAuth2 framework. There are still many things that we can add to the application.

Don’t hesitate to contribute to the project. And remember to leave a star! :)

Focus On Idea And Get Security For Free

No doubts that security and privacy are the most important things nowadays. Having many years of experience we know how to protect your users. Let them trust you!

Schedule a call with our expert
comments powered by Disqus