Securing a Spring Boot REST API with Okta
In this section, we will learn how to secure a Spring Boot REST API with Okta.
What is Okta?
Okta is primarily cloud-based identity and access management software that enables secure authentication, Single Sign-On (SSO), Active Directory (AD) and LDAP integration, the centralized deprovisioning of users, multifactor authentication (MFA), mobile identity management, and flexible policies for organization security and control.
Okta’s basis is based on the notion of Identity as a Service (IDaaS), which provides enterprises with a comprehensive solution for identity and access management. More Info - click here
Why Do We Use Okta?
1. Increased Security
It provides a strong and secure authentication architecture that protects enterprises against illegal access and data breaches.
2. Better User Experience
Users can access all applications with only one set of credentials thanks to Okta's single sign-on (SSO) capabilities, which make for a faster and more effective user experience.
3. Productivity
Okta boosts productivity by making application access faster and easier.
4. Scalability and Flexibility
Okta solutions are scalable to meet the growing demands of modern technology landscapes, adaptable to different environments.
5. Governance and Compliance
Okta ensures adherence to regulatory requirements and compliance standards, instilling trust among customers and partners.
6. Cost savings
Okta reduces the need for IT specialists and streamlines user account management, saving enterprises time and money.
7. Enhanced collaboration
Okta's API access control tools let developers build safe and smooth interfaces between apps, facilitating communication and information sharing between teams.
More Info - click here
Let's go through a simple example,
1. Register to Okta
Go to okta signup page using https://developer.okta.com/signup/ link, We will be taken to a page like the below image,
Then click on the "Sign up free for Developer Edition" button. We will be taken to a page like the below image,
We can register by entering our personal information and click on "Sign up" button or We can register by clicking "Continue with GitHub" or "Continue with Google". I am using my Google account to register to Okta.
Okta will work as authorization server and for our API it will give us access token. Only when we have the access token we will be able to access the secured API's in our application.
2. Create an application in Okta
Next we need to create an application in Okta.
Navigate to "Applications" on the left panel and select the "application" option from the dropdown list and then click on "Create App Integration" like below image.
After clicking "Create App Integration" button, we will see a popup like below image,
Then choose "API Services" and the click on "Next" button. We will be taken to a page like the below image,
Here we have to give the name of our application and then click on "Save" button. We will be taken to a page like the below image,
Remember to have "Client ID" and "Client Secret" safely with us for the future purpose.
Next, navigate to "Security" on the left panel and select the "API" option from the dropdown list.
Remember to have Authorization Server URL "Issuer URI" with us for the future purpose. This is created by Okta by default for us.
3. Create Custom Scope
Scopes are identifiers used to specify what access privileges are being requested.
Click on edit button, We will be taken to a page like the below image,
Click on "Add Scope" button, we will see a popup like below image,
Remember to have custom scope "knowledgefactory" with us for the future purpose.
4. Creating spring boot application
First, open the Spring initializr https://start.spring.io/
Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact spring-boot-okta-secure-rest-api. Here I selected the Maven project - language Java 17 - Spring Boot 3.1.5 , Okta, and Spring Web.
Then, click on the Generate button. When we click on the Generate button, it starts packing the project in a .zip(spring-boot-okta-secure-rest-api) file and downloads the project. Then, Extract the Zip file.
Then, import the project on your favourite IDE.
Final Project Directory
Complete pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-boot-okta-secure-rest-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-okta-secure-rest-api</name>
<description>Demo project for Spring Boot and Okta</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yaml
okta:
oauth2:
issuer: https://<your-domain>/oauth2/default
Specify our issuer uri in application.yaml file.
Create Security Configuration
package com.knf.dev.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/public").permitAll()
.anyRequest().authenticated())
.oauth2ResourceServer((oauth2) -> oauth2
.jwt(Customizer.withDefaults())
)
.build();
}
}
@Configuration annotation indicating that an object is a source of bean definitions. @Configuration classes declare beans through @Bean -annotated methods.
The @EnableWebSecurity helps to configure the Spring security-related beans, here SecurityFilterChain. SecurityFilterChain is used by FilterChainProxy to determine which Spring Security Filter instances should be invoked for the current request. More Info - click here
The requestMatchers() facilitate all the ways of restricting requests that were supported by the removed methods. Here's an example that permits access to the /public endpoint without authentication.
permitAll() method is used to configure access rules for specific endpoints or resources, allowing unrestricted access to them without requiring authentication or authorization. So, here '/public' endpoint has access to any request. But, '/protected' end point is secured. We need access token to access it.
Create DemoController.java
package com.knf.dev.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("/public")
public String publicMsg(){
return "Public...";
}
@GetMapping("/protected")
public String protectedMsg(){
return "Protected...";
}
}
SpringBootOktaSecureRestApiApplication.java
package com.knf.dev.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootOktaSecureRestApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootOktaSecureRestApiApplication.class, args);
}
}
5. Verify our system is working as expected
Run the Spring Boot application - mvn spring-boot:run
OR
Run this Spring boot application from
- IntelliJ IDEA IDE by right click - Run 'Application.main()'
- Eclipse/STS - You can right click the project or the Application.java file and run as java application or Spring boot application.
Run the Spring Boot application - mvn spring-boot:run
OR
Run this Spring boot application from
- IntelliJ IDEA IDE by right click - Run 'Application.main()'
- Eclipse/STS - You can right click the project or the Application.java file and run as java application or Spring boot application.
Get the access token
URL to hit to get the access token -
https://<your-domain>/oauth2/default/v1/token
For Authorization specify, [Username = Client ID and Password = Client Secret]
On request body specify,[grant_type = client_credentials and scope = knowledgefactory] like below images.
We can use this access token as a Bearer Token to hit the secured endpoint,
Remove the token and hit the endpoint again, we will get Status: 401 Unauthorized