
Security is an important part of any web application. This ensures that only the correct users can access preserved resources. In this guide, we will see how to protect the spring boot rest API using okta for authentication and authorization.
We’ll go through:
- Setting up a Spring Boot project
- Configuring Okta for authentication
- Implementing Spring Security
- Creating secured REST endpoints
- Testing with Postman
- Writing unit tests with JUnit & Spring Security
Let’s get started!
1. Project Setup (pom.xml
)
Ensure your pom.xml
includes the required dependencies:
<dependencies>
<!-- Spring Boot Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Okta Spring Boot Starter -->
<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-boot-starter</artifactId>
<version>3.0.7</version>
</dependency>
<!-- Testing Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. Okta Configuration
Step 1: Create an Okta Developer Account
- Sign up at https://developer.okta.com
- Create an Authorization Server under Security → API
- Register a new application:
- Select OIDC - OpenID Connect
- Choose Web as the platform
- Set the redirect URI to
http://localhost:8080/login/oauth2/code/okta
- Note down the following details from Okta Dashboard:
- Issuer URL:
https://your-okta-domain/oauth2/default
- Client ID:
your-client-id
- Client Secret:
your-client-secret
- Issuer URL:
Step 2: Configure application.yml
Create an application.yml
file:
spring:
security:
oauth2:
client:
registration:
okta:
client-id: your-client-id
client-secret: your-client-secret
scope: openid, profile, email
provider:
okta:
issuer-uri: https://your-okta-domain/oauth2/default
3. Spring Security Configuration
Create a security configuration class to define role-based access:
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public").permitAll()
.requestMatchers("/admin").hasAuthority("SCOPE_admin")
.requestMatchers("/user").hasAuthority("SCOPE_user")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
return new JwtAuthenticationConverter();
}
}
This configuration ensures that:
- Public endpoints (
/public
) are accessible to everyone. - User endpoints (
/user
) require theSCOPE_user
role. - Admin endpoints (
/admin
) require theSCOPE_admin
role.
4. Creating Secure REST Endpoints
Now, create a controller with endpoints secured by Spring Security:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/public")
public String publicEndpoint() {
return "This is a public endpoint.";
}
@GetMapping("/user")
public String userEndpoint(@AuthenticationPrincipal Jwt jwt) {
return "Hello User! Your email: " + jwt.getClaim("email");
}
@GetMapping("/admin")
public String adminEndpoint(@AuthenticationPrincipal Jwt jwt) {
return "Hello Admin! Your email: " + jwt.getClaim("email");
}
}
5. Testing with Postman
Step 1: Get Access Token
- Open Postman and create a POST request.
- Use the following Okta OAuth 2.0 Token Endpoint:
https://your-okta-domain/oauth2/default/v1/token
- Set the request Body to
x-www-form-urlencoded
with:grant_type
:client_credentials
client_id
:your-client-id
client_secret
:your-client-secret
scope
:openid profile email user admin
- Click Send and copy the
access_token
.
Step 2: Access API Endpoints
Public Endpoint (No Token Required)
GET http://localhost:8080/api/public
User Endpoint (Requires Token)
GET http://localhost:8080/api/user
Add Authorization Header: Bearer <your-access-token>
Admin Endpoint (Requires Token with SCOPE_admin
)
GET http://localhost:8080/api/admin
Add Authorization Header: Bearer <your-access-token>
6. Unit Testing with JUnit & Spring Security
Write tests to verify security constraints:
package com.example.demo;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@SpringBootTest
@AutoConfigureMockMvc
class ApiControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void testPublicEndpoint() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/public"))
.andExpect(status().isOk());
}
@Test
void testUserEndpoint() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/user")
.with(jwt().jwt(jwt -> jwt.claim("scope", "user"))))
.andExpect(status().isOk());
}
@Test
void testAdminEndpoint() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/admin")
.with(jwt().jwt(jwt -> jwt.claim("scope", "admin"))))
.andExpect(status().isOk());
}
@Test
void testUnauthorizedAdminAccess() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/admin")
.with(jwt().jwt(jwt -> jwt.claim("scope", "user"))))
.andExpect(status().isForbidden());
}
}
🌿 Secure Your Spring Boot App with Okta
Get started with a fully secure Spring Boot project integrated with Okta OAuth 2.0 authentication.
🚀 Clone on GitHub