Secure a Spring Boot REST API with JSON Web Token

Plus references to Angular integration

Nouhoun Y. Diarra
May 15, 2017 · 7 min read

In this piece, I am going to walk you through how to secure a Spring Boot REST API with JSON Web Token (JWT) to exchange claims between a server and a client. This is Part two of a collaborative effort between my colleague Julia Passynkova and myself demonstrating how to secure an Angular 2+ application using Spring Boot as a RESTful back end. If you are impatient or prefer to learn directly from the code, check out the code in the Github repository. You can find the Angular integration project here.


A Quick Intro

Over the past few years, Spring Boot has greatly simplified the configuration of Spring Framework applications. The unceremonious approach it takes lets developers enable basic security for an application by simply having Spring Security dependency on the classpath.

Choosing JWT to secure your API endpoints is a great choice because it ensures a stateless exchange of tokens between the client and the server, and is compact and URL-safe. With JWT, it is not necessary to store access tokens in a database (although you may still do that and even need to depending on the use case) or worry about sticky sessions. This makes building redundancy into your enterprise application more cost-effective, at least as far as the security aspect is concerned. You do, however, need to deal with other aspects such as token revocation, but that is not covered here. The basis for understanding how useful JWT is is to first grasp OAuth 2.0. For a quick reference, below is an illustration of the OAuth dance.

Illustration of OAUTH 2. dance

What you will need for the project?

1. Spring Boot 1.5.3.RELEASE project with either Maven or Gradle. This project uses Maven.

2. The following dependencies:

  • — H2 Database for storing sample test data
  • version: 1.0.7.RELEASE
  • version: 2.1.0.RELEASE

Final project structure

When you clone the project from Github and import it into your IDE, for instance, its structure will look similar to the following. Here, I am using a screenshot from IntelliJ Community Edition IDE. Yours will look slightly different depending on the IDE you use.


1. Configure Spring Security

Thanks to Spring Boot’s autoconfiguration we will need minimal customizations to get set:

First, let’s look at the application’s configuration file, :

Then the security configuration class:

  • : Enables spring security and tells Spring Boot to apply all the sensitive defaults
  • : Allows us to have method level access control
  • and beans: A bean is needed by the authorization server and to enable the resource server to decode access tokens a bean must be used by both servers. In this case, we are providing a symmetric key signing.
  • : We inject a custom implementation of , named (see the code on GitHub for details) in order to retrieve user details from the database.
  • Encoding: SHA-256 is used to encode passwords. This is set in property
  • Realm: The security realm name is defined in property. This name is arbitrary. A realm is basically all that define our security solution from the provider to roles, users, etc.

2. Configure Authorization Server

  • : Enables an authorization server
  • which is our authorization server configuration class extends which in turn is an implementation of . The presence of a bean of type simply tells Spring Boot to switch off auto-configuration and use the custom configuration. Also, the , like any other configuration class, has its definition automatically scanned, wired, and applied by Spring Boot because of the annotation.
  • Client id: defines the id of the client application that is authorized to authenticate, the client application provides this in order to be allowed to send a request to the server.
  • Client secret: is the client application’s password. In a non-trivial implementation client ids and passwords will be securely stored in a database and retrievable through a separate API that clients applications access during deployment. These pieces of information can also be shared and stored in environment variables although that would not be my preferred option.
  • Grant type: we define the grant type password here because it’s not enabled by default
  • The scope: read/write defines the level of access we are allowing to resources
  • Resource Id: The resource id specified here must be specified on the resource server as well
  • AuthenticationManager: Spring’s authentication manager takes care of checking user credential validity
  • TokenEnhancerChain: We define a token enhancer that enables chaining multiple types of claims containing different information

3. Configure the Resource Server

: Enables a resource server. By default, this annotation creates a security filter which authenticates requests via an incoming OAuth2 token. The filter is an instance of which has an hard-coded order of three (Due to some limitations of Spring Framework). You need to tell Spring Boot to set the OAuth2 request filter order to three to align with the hardcoded value. You do that by adding in the file. Hopefully, this will be fixed in future releases.

The resource server has the authority to define the permission for any endpoint. The endpoint permission is defined with:

Notice here that the resource and the authorization servers both use the same token service. That is because they are in the same code base so we are reusing the same bean.


4. Configure a Data Source

Spring Boot can fully auto-configure the in-memory H2 data source once it’s defined on the classpath. However, to give you a better sense of how you can take control of your application and customize your data source the following configuration is provided:

Replace H2 with any database (MariaDB, MySQL, Oracle, SQL Server, etc.) to fit your use case.


5. Database Scripts and Test Data

data.sql


6. Entities

User, Role, RandomCity entities are created to map to the data model


7. Exposing Resources via a REST Controller

Here two endpoints are exposed

  • : This endpoint is accessible to all authenticated users
  • : This endpoint is accessible only to an admin user

8. Running and Testing the Application

First, you will need the following basic pieces of information:

Step 1: Generate an access token

Use the following generic command to generate an access token:

For this specific application, to generate an access token for the non-admin user , run: . You'll receive a response similar to below:

`
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdGp3dHJlc291cmNlaWQiXSwidXNlcl9uYW1lIjoiYWRtaW4uYWRtaW4iLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNDk0NDU0MjgyLCJhdXRob3JpdGllcyI6WyJTVEFOREFSRF9VU0VSIiwiQURNSU5fVVNFUiJdLCJqdGkiOiIwYmQ4ZTQ1MC03ZjVjLTQ5ZjMtOTFmMC01Nzc1YjdiY2MwMGYiLCJjbGllbnRfaWQiOiJ0ZXN0and0Y2xpZW50aWQifQ.rvEAa4dIz8hT8uxzfjkEJKG982Ree5PdUW17KtFyeec",
"token_type": "bearer",
"expires_in": 43199,
"scope": "read write",
"jti": "0bd8e450-7f5c-49f3-91f0-5775b7bcc00f"
}`

Step 2: Use the token to access resources through your RESTful API

Use the token to access resources through your RESTful API

To access content available to all authenticated users:

  • Use the generated token as the value of the Bearer in the Authorization header as follows:
  • The response will be:

To access content available only to an admin user:

As with the previous example, first, generate an access token for the admin user with the credentials provided above then run

The result will be:


9. Access a non-secure or non-protected endpoint

The http://localhost:8080/health is not restricted. This is accessible to anonymous users and can be used for load balancing health check purpose.


References & Useful Readings:

Better Programming

Advice for programmers.

Nouhoun Y. Diarra

Written by

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade