DEV Community

Cover image for Create a Secure Spring REST API
OktaDev for Okta

Posted on • Originally published at developer.okta.com on

Create a Secure Spring REST API

“If it is useful, it will be modified.” Those words of wisdom came from a QA teacher of mine, to explain that all software evolves when it becomes useful to someone, and for as long as it is useful. We all know this. Users ask us for new features, bug fixes, and changes in domain logic every day. As any project (especially a monolith) grows, it can begin to become difficult to maintain, and the barrier to entry for anyone new just gets higher and higher. In this tutorial, I’m excited to walk you through building a secure Spring REST API that tries to solve for some of these pain points using a microservices architecture.

In a microservices architecture, you logically divide your application into several apps that can be more easily maintained and scaled, use different stacks, and support more teams working in parallel. But microservices are the simple solution to every scaling and maintenance problem.

Microservices also present a number of architectural challenges that must be addressed:

  • How those services communicate?
  • How should communication failures and availability be handled?
  • How can a user’s requests be traced between services?
  • And, how should you handle user authorization to access a single service?

Let’s dig in and find out how to address these challenges when building a Spring REST API.

Secure Your Spring REST API with OAuth 2.0

In OAuth 2.0, a resource server is a service designed to handle domain-logic requests and does not have any kind of login workflow or complex authentication mechanism: it receives a pre-obtained access token that guarantees a user have grant permission to access the server and delivers the expected response.

In this post, you are going to build a simple Resource Server with Spring Boot and Okta to demonstrate how easy it is. You will to implement a simple Resource Server that will receive and validate a JWT Token.

Add a Resource Server Your Spring REST API

This example uses Okta to handle all authentication process. You can register for a free-forever developer account that will enable you to create as many users and applications you need.

I have set up some things so we can get started easily. Please clone the following resource repository and go to startup tag, as follows:

git clone -b startup https://github.com/oktadeveloper/okta-secure-spring-rest-api-example secure-spring-rest-api
cd secure-spring-rest-api

Enter fullscreen mode Exit fullscreen mode

This project has the following structure:

$ tree .
.
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │ ├── java
    │ │ └── net
    │ │ └── dovale
    │ │ └── okta
    │ │ └── secure_rest_api
    │ │ ├── HelloWorldController.java
    │ │ ├── SecureRestApiApplication.java
    │ │ └── SecurityConfig.java
    │ └── resources
    │ └── application.properties
    └── test
        └── java
            └── net
                └── dovale
                    └── okta
                        └── secure_rest_api
                            └── SecureRestApiApplicationTests.java

14 directories, 9 files

Enter fullscreen mode Exit fullscreen mode

I created it using the excellent Spring Initializr and adding Web and Security dependencies. Spring Initializr provides an easy way to create a new Spring Boot service with some common auto-discovered dependencies. It also adds the Maven Wrapper: so you use the command mvnw instead of mvn, the tool will detect if you have the designated Maven version and, if not, it will download and run the specified command.

Fun fact: Did you know the Maven wrapper was originally created by Okta’s own Brian Demers?!

The file HelloWorldController is a simple @RestController that outputs “Hello World”.

In a terminal, you can run the following command and see Spring Boot start:

mvnw spring-boot:run

Enter fullscreen mode Exit fullscreen mode

TIP: If this command doesn’t work for you, try ./mvnw spring-boot:run instead.

Once it finishes loading, you’ll have a REST API ready and set to deliver to you a glorious Hello World message!

> curl http://localhost:8080/
Hello World

Enter fullscreen mode Exit fullscreen mode

TIP: The curl command is not available by default for Windows users. You can download it from here.

Now, you need to properly create a protected Resource Server.

Set Up an OAuth 2.0 Resource Server

In the Okta dashboard, create an application of type Service it indicates a resource server that does not have a login page or any way to obtain new tokens.

Create new Service

Click Next, type the name of your service, then click Done. You will be presented with a screen similar to the one below. Copy and paste your Client ID and Client Secret for later. They will be useful when you are configuring your application.

Service Created

Now, let’s code something!

Edit the pom.xml file and add dependencies for Spring Security and Okta. They will enable all the Spring AND Okta OAuth 2.0 goodness you need:

<!-- security - begin -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
    <groupId>com.okta.spring</groupId>
    <artifactId>okta-spring-boot-starter</artifactId>
    <version>0.6.1</version>
</dependency>
<!-- security - end -->

Enter fullscreen mode Exit fullscreen mode

By simply adding this dependency, your code is going to be like a locked house without a key. No one can access your API until you provide a key to your users. Run the command below again.

mvnw spring-boot:run

Enter fullscreen mode Exit fullscreen mode

Now, try to access the Hello World resource:

> curl http://localhost:8080/
{"timestamp":"2018-11-30T01:35:30.038+0000","status":401,"error":"Unauthorized","message":"Unauthorized","path":"/"}

Enter fullscreen mode Exit fullscreen mode

Add Spring Security to Your REST API

Spring Boot has a lot of classpath magic and is able to discover and automatically configure dependencies. Since you have added Spring Security, it automatically secured your resources. Now, you need to configure Spring Security so you can properly authenticate the requests.

NOTE: If you are struggling, you can check the modifications in Git branch step-1-security-dependencies.

For that, you need to modify application.properties as follows (use client_id and client_secret provided by Okta dashboard to your application):

okta.oauth2.issuer=https://{yourOktaDomain}/oauth2/default
okta.oauth2.clientId={clientId}
okta.oauth2.clientSecret={clientSecret}
okta.oauth2.scopes=openid

Enter fullscreen mode Exit fullscreen mode

Spring Boot uses annotations and code for configuring your application so you do not need to edit super boring XML files. This means you can use the Java compiler to validate your configuration!

I usually create configuration in different classes, each one have its own purpose. Create the class net.dovale.okta.secure_rest_api.SecurityConfig as follows:

package net.dovale.okta.secure_rest_api;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

@EnableWebSecurity
@EnableResourceServer
public class SecurityConfig {}

Enter fullscreen mode Exit fullscreen mode

Allow me to explain what the annotations here do:

  • @EnableWebSecurity - tells spring we are going to use Spring Security to provide web security mechanisms.
  • @EnableResourceServer - convenient annotation that enables request authentication through OAuth 2.0 tokens. Normally, you would provide a ResourceServerConfigurer bean, but Okta’s Spring Boot starter conveniently provides one for you.

That’s it! Now you have a completely configured and secured Spring REST API without any boilerplate!

Run Spring Boot again and check it with cURL.

mvnw spring-boot:run
# in another shell
curl http://localhost:8080/
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}

Enter fullscreen mode Exit fullscreen mode

The message changed, but you still without access… why? Because now the server is waiting for an authorization header with a valid token. In the next step, you’ll create an access token and use it to access your API.

NOTE: Check the Git branchstep-2-security-configuration if you have any doubt.

Generate Tokens in Your Spring REST API

So… how do you obtain a token? A resource server has no responsibility to obtain valid credentials: it will only check if the token is valid and proceed with the method execution.

An easy way to achieve a token to generate one using OpenID Connect .

First, you’ll need to create a new Web application in Okta:

New web application

Set the Login redirect URIs field to https://oidcdebugger.com/debug and Grant Type Allowed to Hybrid. Click Done and copy the client ID for the next step.

Now, on the OpenID Connect website, fill the form in like the picture below (do not forget to fill in the client ID for your recently created Okta web application):

OpenID connect

Submit the form to start the authentication process. You’ll receive an Okta login form if you are not logged in or you’ll see the screen below with your custom token.

OpenID connect - getting token

The token will be valid for one hour so you can do a lot of testing with your API. It’s simple to use the token, just copy it and modify the curl command to use it as follows:

> export TOKEN=${YOUR_TOKEN}
> curl http://localhost:8080 -H "Authorization: Bearer $TOKEN"
Hello World

Enter fullscreen mode Exit fullscreen mode

Add OAuth 2.0 Scopes

OAuth 2.0 scopes is a feature that let users decide if the application will be authorized to make something restricted. For example, you could have “read” and “write” scopes. If an application needs the write scope, it should ask the user this specific scope. These can be automatically handled by Okta’s authorization server.

As a resource server, it can have different endpoints with different scope for each one. Next, you are going to learn how to set different scopes and how to test them.

Add a new annotation to your SecurityConfig class:

@EnableWebSecurity
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {}

Enter fullscreen mode Exit fullscreen mode

The new @EnableGlobalMethodSecurity(prePostEnabled = true) annotation tells Spring to use AOP-like method security and prePostEnabled = true will enable pre and post annotations. Those annotations will enable us to define security programmatically for each endpoint.

Now, make changes to HelloWorldController.java to create a scope-protected endpoint:

import org.springframework.security.access.prepost.PreAuthorize;
import java.security.Principal;
...
@PreAuthorize("#oauth2.hasScope('profile')")
@GetMapping("/protected/")
public String helloWorldProtected(Principal principal) {
    return "Hello VIP " + principal.getName();
}

Enter fullscreen mode Exit fullscreen mode

Pay attention to @PreAuthorize("#oauth2.hasScope('profile')"). It says: before running this method, verify the request has authorization for the specified Scope. The #oauth2 bit is added by OAuth2SecurityExpressionMethods (check the other methods available) Spring class and is added to your classpath through the spring-cloud-starter-oauth2 dependency.

OK! After a restart, your server will be ready! Make a new request to the endpoint using your current token:

> curl http://localhost:8080/protected/ -H "Authorization: Bearer $TOKEN"
{"error":"access_denied","error_description":"Access is denied"}

Enter fullscreen mode Exit fullscreen mode

Since your token does not have the desired scope, you’ll receive an access is denied message. To fix this, head back over to OIDC Debugger and add the new scope.

Profile scope

Try again using the newly obtained token:

> curl http://localhost:8080/protected/ -H "Authorization: Bearer $TOKEN"
Hello VIP raphael@dovale.net

Enter fullscreen mode Exit fullscreen mode

That’s it! If you are in doubt of anything, check the latest repository branch finished_sample.

TIP: Since profile is a common OAuth 2.0 scope, you don’t need to change anything in your authorization server. Need to create a custom scope? See this Simple Token Authentication for Java Apps.

Learn More about Spring and REST APIs

In this tutorial, you learned how to use Spring (Boot) to create a resource server and seamlessly integrate it with OAuth 2.0. Both Spring and REST API’s are huge topics, with lots to discuss and learn.

The source code for this tutorial is available on GitHub.

Here are some other posts that will help you further your understanding of both Spring and REST API security:

Like what you learned today? Follow us on Twitter, like us on Facebook, check us out on LinkedIn, and subscribe to our YouTube channel.

Top comments (0)