OAuth implementation in Spring Security. Part 1

There is often little time for safety during development, but it is a very important issue. In this series of articles, I will try to describe as simply as possible the main technologies to make your application secure.

In this article we will talk about OAuth. It is an older standard of user authorization, but still very popular in modern internet microservice architecture. Where do we start?

So, what is OAuth? It is a protocol that allows users to delegate their permissions from one service to others. Why is it needed? Could we live without this technology?

For example, say that you want to collect all emails from multiple services and accounts. You would give this service your login and password from all other services. You can do this, but is it safe? One service has all your login names and passwords from all your accounts. Your data will be stored explicitly. It is extremely unsafe, and your data could be compromised.

OAuth technology was developed to solve this problem. With this technology, you don’t need to give all your credentials and control of your accounts to a third party. The OAuth protocol has many usage scenarios. So, we will start with the most common one.

In this scenario, we have a user, our application, and a third-party service with resources we want to use.

Although our application cannot store user information (login and password), we need to save and use a temporary login and password to give us access to user information on another server. In this situation, we must ask the user to create these credentials for us.

The user wants to interact with our service, obtain some data from a third-party service, and use it in our service. In this situation, the user makes a request to our service. At this time we do not yet have access to this other service, so we send a response to the user, to request access to their data from another resource. The user makes a second request to this third-party service with their credentials, then transfers their use information to the service. At this point, the third-party service then accepts our service, and gives it an authorization token containing a special authorization code and client id for our service.

With this information, we are now able to make a request to the other service and receive a special resource token.

This token allows access to resources that the third-party service provides.

So, as you can see, the authorization operation is a bit different from simply getting resources, but it looks very similar.

This sequence of steps calls OAuth flow, or more precisely, “grant authorization code”. OAuth protocol also provides other flows to customers. For example, we won’t use this type of flow, because our microservices talk to each other without the user authorization step. In this situation, login name and password could be saved by the user in our microservice. It makes a request to a third-party service with login and password, then the third-party service will check it and return authorization token if credentials are valid.

This flow is called OAuth password grand type.

The last type of interaction between services is shown in the figure below:

This interaction is useful if we don’t have any credentials from the user, and we won’t bypass OAuth protocol between internal services.

To avoid security problems with token interception, the protocol has a mechanism to refresh tokens. Each resource token has an expiry date that can be used only for a short period of time. If our service cannot get data from another service, it makes a request to refresh the token. The authorization server knows about this token, and gives a response with a new resource token. Using this token, our service is again able to access a resource until this new token expires.

OAuth given to our application is only key to user resources, but we cannot recognize our user; we literally know nothing about them. So OAuth has an add-on that is able to transmit not just a token, but also a user’s profile with basic information about the user. This technology is called “OpenId connection”, and it allows the use of a single credential across multiple services. This is also known as a single sign-on. Many internet users are probably already familiar with this. For example, we can log into many sites and services using the same Gmail account.

What is the difference between OpenId and the first example from the top of this article? After a user request, our service makes an authorization request to a third-party service. It contains the following fields:

response_type — the type of response (for example, “code”)

client_id — unique identification of our service

redirect_uri — A redirect URI (or URL) that the third-party server redirects to after successful authentication.

scope — type of permission requested

So for the scope variable, we will add the “OpenID” string. A third-party server that supports OpenID will recognize this string, and then add the user information to the ID token in response.

What is an ID token? This is a JSON web token (JWT):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlJvbWFuIEl2YW5vdiIsImlhdCI6MTIzNDU2NywiZXhwaXJhdGlvbiI6InRvbW9ycm93IiwidXNlcl9jcmVkZW50aWFsIjoic2VhcmNoIGluIGdvb2dsZSJ9.sN22rnivD-mPm6W9hxJNoPL3T2qbYk6zfYC9YtItjHo

This string is a base64-encoded string with three sections. The first part contains information about the hashing algorithm and token type contained within. The second part contains all information about the user, session, permits, etc. The last section contains a resource owner’s signature. Only the resource server has the special password needed generate this electronic signature. I will discuss this in the next article.

For now, let’s write a simple app that uses OAuth, based on the spring security framework.

We will use the GitHub authorization server to log into our app. First, we need to register the application:

GitHub will give us the client id and secret client code. We will then give this information to our application.

We need to add this information to our property file:

After this, we must configure the application’s web configuration:

PrincipalExtractor is a functional interface:

We need to determine the implementation, which handles Map<String, Object> map. In this map, a third-party service will handle all requested information about the user, such as unique id, name, email, etc. Our custom UserHandleService will process this map and return user information in our custom format.

Our application is now ready! In this short example, we have learned how to perform authorization via OAuth technology, and obtain info about the user from a third-party service. In the next part, we will demonstrate more examples of coding with a custom authorization server. Stay tuned!

Passionate about Java and quantum mechanics

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store