Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

Join us at AWS re:Invent 2024! Learn how to use MongoDB for AI use cases.
MongoDB Developer
Java
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
Javachevron-right

Secure your API with Spring Data MongoDB and Microsoft EntraID

Tim Kelly8 min read • Published Apr 02, 2024 • Updated Apr 02, 2024
AzureSpringMongoDBJava
FULL APPLICATION
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Introduction

Welcome to our hands-on tutorial, where you'll learn how to build a RESTful API with Spring Data MongoDB, fortified by the security of Microsoft Entra ID and OAuth2. On this journey, we'll lead you through the creation of a streamlined to-do list API, showcasing not just how to set it up, but also how to secure it effectively.
This guide is designed to provide you with the tools and knowledge needed to implement a secure, functional API from the ground up. Let's dive in and start building something great together!

Prerequisites

You can follow along with this tutorial and build your project as you read or you can clone the repository directly:
1git clone git@github.com:mongodb-developer/java-spring-boot-secure-todo-app.git

Create our API with Spring Data MongoDB

Once these prerequisites are in place, we're ready to start setting up our Spring Boot secure RESTful API. Our first step will be to lay the foundation with application.properties.
1spring.application.name=todo
2spring.cloud.azure.active-directory.enabled=true
3spring.cloud.azure.active-directory.profile.tenant-id=<YOUR-TENANT-ID>
4spring.cloud.azure.active-directory.credential.client-id=<YOUR-APPLICATION-ID>
5spring.security.oauth2.client.registration.azure.client-authentication-method=none
6spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.microsoftonline.com/<YOUR-TENANT-ID/v2.0
7server.forward-headers-strategy=framework
8springdoc.swagger-ui.use-root-path=true
9springdoc.swagger-ui.oauth.use-pkce-with-authorization-code-grant=true
10spring.security.oauth2.client.registration.azure.redirect-uri=http:<YOUR-APPLICATION-URL>/swagger-ui/oauth2-redirect.html
11spring.data.mongodb.uri=<YOUR-MONGODB-CONNECTION-URI>
12spring.data.mongodb.database=<YOUR-MONGODB-DATABASE>
  • spring.application.name=todo: Defines the name of your Spring Boot application
  • spring.cloud.azure.active-directory...: Integrates your application with Azure AD for authentication and authorization
  • spring.security.oauth2.client.registration.azure.client-authentication-method=none: Specifies the authentication method for the OAuth2 client; setting it to none is used for public clients, where a client secret is not applicable
  • spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.microsoftonline.com/<YOUR-TENANT-ID/v2.0: Configures your application as an OAuth2 resource server, validating JWT tokens issued by Azure AD
  • server.forward-headers-strategy=framework: Configures how your application handles forwarded headers, which is important for applications behind proxies or load balancers, especially in regard to constructing correct URLs for redirects
  • springdoc.swagger-ui...: Configure Swagger UI, specifically enabling it to run on the root path and to use Proof Key for Code Exchange (PKCE) with the OAuth2 authorization code grant
Create a package called model and add the class Todo. Here, we will have our POJO that maps to our documents in our MongoDB database.
1package com.example.todo.model;
2
3import org.springframework.data.annotation.Id;
4import org.springframework.data.mongodb.core.mapping.Document;
5
6@Document
7public class Todo {
8 @Id
9 private String id;
10 private String title;
11 private boolean completed;
12
13 // Constructors, getters, and setters
14}
Create a separate package called repository with the interface TodoRepository. To make our lives easier, we are going to use MongoRepository. This will allow us to use the CRUD operations on our MongoDB database without having to set up all our boilerplate code.
1package com.example.todo.model.repository;
2
3import com.example.todo.model.Todo;
4import org.springframework.data.mongodb.repository.MongoRepository;
5
6public interface TodoRepository extends MongoRepository<Todo, String> {
7}
Next, create a service package and a class TodoService. This will contain our business logic for our application.
1package com.example.todo.service;
2
3import org.springframework.beans.factory.annotation.Autowired;
4import org.springframework.stereotype.Service;
5
6import com.example.todo.model.Todo;
7import com.example.todo.model.repository.TodoRepository;
8
9import java.util.List;
10import java.util.Optional;
11
12@Service
13public class TodoService {
14
15private final TodoRepository todoRepository;
16
17 public TodoService(TodoRepository todoRepository) {
18 this.todoRepository = todoRepository;
19 }
20
21 public List<Todo> findAll() {
22 return todoRepository.findAll();
23 }
24
25 public Optional<Todo> findById(String id) {
26 return todoRepository.findById(id);
27 }
28
29 public Todo save(Todo todo) {
30 return todoRepository.save(todo);
31 }
32
33 public void deleteById(String id) {
34 todoRepository.deleteById(id);
35 }
36}
To establish your API endpoints, create a controller package and a TodoController class. There are a couple things going on here. For each of the API endpoints we want to restrict access to, we use @PreAuthorize("hasAuthority('SCOPE_Todo.<SCOPE>')") where <SCOPE> corresponds to the scopes we will define in Microsoft Entra ID.
We have also disabled CORS here. In a production application, you will want to specify who can access this and probably not just allow all, but this is fine for this tutorial.
1package com.example.todo.controller;
2
3import com.example.todo.model.Todo;
4import com.example.todo.sevice.TodoService;
5
6import org.springframework.beans.factory.annotation.Autowired;
7import org.springframework.security.access.prepost.PreAuthorize;
8import org.springframework.security.core.Authentication;
9import org.springframework.web.bind.annotation.*;
10import java.util.List;
11
12@CrossOrigin(origins = "*")
13@RestController
14@RequestMapping("/api/todos")
15public class TodoController {
16
17 public TodoController(TodoService todoService) {
18 this.todoService = todoService;
19 }
20
21 @GetMapping
22 public List<Todo> getAllTodos() {
23 return todoService.findAll();
24 }
25
26 @GetMapping("/{id}")
27 public Todo getTodoById(@PathVariable String id) {
28 return todoService.findById(id).orElse(null);
29 }
30
31 @PostMapping
32 @PreAuthorize("hasAuthority('SCOPE_Todo.User')")
33 public Todo createTodo(@RequestBody Todo todo, Authentication authentication) {
34 return todoService.save(todo);
35 }
36
37 @PutMapping("/{id}")
38 @PreAuthorize("hasAuthority('SCOPE_Todo.User')")
39 public Todo updateTodo(@PathVariable String id, @RequestBody Todo todo) {
40 return todoService.save(todo);
41 }
42
43 @DeleteMapping("/{id}")
44 @PreAuthorize("hasAuthority('SCOPE_Todo.Admin')")
45 public void deleteTodo(@PathVariable String id) {
46 todoService.deleteById(id);
47 }
48}
Now, we need to configure our Swagger UI for our app. Create a config package and an OpenApiConfiguration class. A lot of this is boilerplate, based on the demo applications provided by springdoc.org. We're setting up an authorization flow and specifying the scopes available in our application. We'll create these in a later part of this application, but pay attention to the API name when setting scopes (.addString("api://todo/Todo.User", "Access todo as a user"). You have an option to configure this later but it needs to be the same in the application and on Microsoft Entra ID.
1package com.example.todo.config;
2
3import io.swagger.v3.oas.models.Components;
4import io.swagger.v3.oas.models.OpenAPI;
5import io.swagger.v3.oas.models.info.Info;
6import io.swagger.v3.oas.models.security.OAuthFlow;
7import io.swagger.v3.oas.models.security.OAuthFlows;
8import io.swagger.v3.oas.models.security.Scopes;
9import io.swagger.v3.oas.models.security.SecurityScheme;
10
11import org.springframework.beans.factory.annotation.Value;
12import org.springframework.context.annotation.Bean;
13import org.springframework.context.annotation.Configuration;
14
15
16@Configuration
17class OpenApiConfiguration {
18
19 @Value("${spring.cloud.azure.active-directory.profile.tenant-id}")
20 private String tenantId;
21
22 @Bean
23 OpenAPI customOpenAPI() {
24 OAuthFlow authorizationCodeFlow = new OAuthFlow();
25 authorizationCodeFlow.setAuthorizationUrl(String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/authorize", tenantId));
26 authorizationCodeFlow.setRefreshUrl(String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId));
27 authorizationCodeFlow.setTokenUrl(String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId));
28 authorizationCodeFlow.setScopes(new Scopes()
29 .addString("api://todo/Todo.User", "Access todo as a user")
30 .addString("api://todo/Todo.Admin", "Access todo as an admin"));
31 OAuthFlows oauthFlows = new OAuthFlows();
32 oauthFlows.authorizationCode(authorizationCodeFlow);
33 SecurityScheme securityScheme = new SecurityScheme();
34 securityScheme.setType(SecurityScheme.Type.OAUTH2);
35 securityScheme.setFlows(oauthFlows);
36 return new OpenAPI()
37 .info(new Info().title("RESTful APIs for Todo"))
38 .components(new Components().addSecuritySchemes("Microsoft Entra ID", securityScheme));
39 }
40}
The last thing we need to do is create a WebConfig class in our config package. Here, we just need to disable Cross-Site Request Forgery (CSRF).
1package com.example.todo.config;
2
3import org.springframework.context.annotation.Bean;
4import org.springframework.context.annotation.Configuration;
5import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6import org.springframework.security.web.SecurityFilterChain;
7import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
8
9
10@Configuration
11public class WebConfig {
12
13 @Bean
14 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
15 http.csrf(AbstractHttpConfigurer::disable);
16 return http.build();
17 }
18}
When using OAuth for authentication in a web application, the necessity of CSRF tokens depends on the specific context of your application and how OAuth is being implemented.
In our application, we are using a single-page application (SPAs) for interacting with our API. OAuth is often used with tokens (such as JWTs) obtained via the OAuth Authorization Code Flow with PKCE so the CSRF is not necessary. If your application still uses cookies (traditional web access) for maintaining session state post-OAuth flow, implement CSRF tokens to protect against CSRF attacks. For API serving an SPA, we will rely on bearer tokens.

Expose your RESTful APIs in Microsoft Entra ID

It is time to register a new application with Microsoft Entra ID (formerly known as Azure Active Directory) and get everything ready to secure our RESTful API with OAuth2 authentication and authorization. Microsoft Entra ID is a comprehensive identity and access management (IAM) solution provided by Microsoft. It encompasses various services designed to help manage and secure access to applications, services, and resources across the cloud and on-premises environments.
  1. Sign in to the Azure portal. If you have access to multiple tenants, select the tenant in which you want to register an application.
  2. Search for and select the Microsoft Entra ID service.
    • If you don't already have one, create one here.
  3. From the left side menu, under Manage, select App registrations and New registration.
  4. Enter a name for your application in the Name field. For this tutorial, we are going to stick with the classic CRUD example, a to-do list API, so we'll call it TodoAPI.
  5. For Supported account types, select Accounts in any organizational directory (Any Microsoft Entra directory - Multitenant) and personal Microsoft accounts. This will allow the widest set of Microsoft entities.
  6. Select Register to create the application.
  7. On the app Overview page, look for the Application (client) ID value, and then record it for later use. You need it to configure the application.properties file for this app.
  8. Navigate to Manage and click on Expose an API. Locate the Application ID URI at the top of the page and click Add.
  9. On the Edit application ID URI screen, it's necessary to generate a distinctive Application ID URI. Opt for the provided default api://{client ID} or choose a descriptive name like api://todo before hitting Save.
  10. Go to Manage, click on Expose an API, then Add a scope, and provide the specified details:
    • For Scope name, enter ToDo.User.
    • For Who can consent, select Admins and Users.
    • For Admin consent display name, enter Create and edit ToDo data.
    • For Admin consent description, enter Allows authenticated users to create and edit the ToDo data.
    • For State, keep it enabled.
    • Select Add scope.
  11. Repeat the previous steps to add the other scopes: ToDo.Admin, which will grant the authenticated user permission to delete. Now that we have our application created and our EntraID configured, we will look at how to request our access token. At this point, you can upload your API to Azure Spring Apps, following our tutorial, Getting Started With Azure Spring Apps and MongoDB Atlas, but we'll keep everything running local for this tutorial.

Grant access to our client with Swagger

The RESTful APIs serve as a resource server, safeguarded by Microsoft Entra ID. To obtain an access token, you are required to register a different application within Microsoft Entra ID and assign permissions to the client application.

Register the client application

We are going to register a second app in Microsoft Entra ID.
  1. Repeat steps 1 through 6 above, but this time, name your application TodoClient.
  2. On the app Overview page, look for the Application (client) ID value. Record it for later use. You need it to acquire an access token.
  3. Select API permissions and Add a permission.
  4. Under My APIs, select the TodoAPI application that you registered earlier. Choose the permissions your client application needs to operate correctly. In this case, select both ToDo.Admin and ToDo.User permissions. Confirm your selection by clicking on Add permissions to apply these to your TodoClient application.
  5. Select Grant admin consent for <YOUR-TENANT-NAME> to grant admin consent for the permissions you added.

Add a user

Now that we have the API created and the client app registered, it is time to create our user to grant permission to. We are going to make a member in our Microsoft Entra tenant to interact with our TodoAPI.
  1. Navigate to your Microsoft Entra ID and under Manage, choose Users.
  2. Click on New user and then on Create new user.
  3. In the Create new user section, fill in User principal name, Display name, and Password. The user will need to change this after their first sign-in.
  4. Click Review + create to examine your entries. Press Create to finalize the creation of the user.

Update the OAuth2 configuration for Swagger UI authorization

To connect our application for this tutorial, we will use Swagger. We need to refresh the OAuth2 settings for authorizing users in Swagger UI, allowing them to get access tokens via the TodoClient application.
  1. Access your Microsoft Entra ID tenant, and navigate to the TodoClient app you've registered.
  2. Click on Manage, then Authentication, choose Add a platform, and select Single-page application. For implicit grant and hybrid flows, choose both access tokens and ID tokens.
  3. In the Redirect URIs section, input your application's URL or endpoint followed by /swagger-ui/oauth2-redirect.html as the OAuth2 redirect URL, and then click on Configure.

Log into your application

Navigate to the app's published URL, then click on Authorize to initiate the OAuth2 authentication process. In the Available authorizations dialog, input the TodoClient app's client ID in the client_id box, check all the options under the Scopes field, leave the client_secret box empty, and then click Authorize to proceed to the Microsoft Entra sign-in page. After signing in with the previously mentioned user, you will be taken back to the Available authorizations dialog. Voila! You should be greeted with your successful login screen.
Swagger authorization screen
Now, we should be ready to test some of our secure endpoints. Send a sample post request using the Swagger UI.
Example post request
If everything is authorized correctly, your data should now be in your MongoDB database.

Wrap up

And there you have it—a journey from the foundations of setting up a MongoDB and Azure environment, through crafting a secure RESTful API with Spring Boot, all the way to testing with Swagger UI. This guide aimed to arm you with the tools to create a robust, secure To-Do list API, demonstrating the power of combining Spring Data MongoDB with the security features of Microsoft Entra ID and OAuth2.
By following through, you've seen how to register and configure your application and client in Microsoft Entra ID, define necessary permissions, and even how to set up users to interact with your API. Your data now securely resides in MongoDB, accessed through a carefully constructed API that respects modern security standards.
If you found this tutorial useful or interesting, check out the Developer Center. Learn to host the API you just built on Azure Spring Apps in Getting Started With Azure Spring Apps and MongoDB Atlas, or read more about securing your data with How to Implement Client-Side Field Level Encryption (CSFLE) in Java with Spring Data MongoDB.
Are you ready to start building with Atlas on Azure? Get started for free today with MongoDB Atlas on Azure Marketplace
Top Comments in Forums
There are no comments on this article yet.
Start the Conversation

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

MongoDB Advanced Aggregations With Spring Boot and Amazon Corretto


Jun 26, 2024 | 5 min read
Tutorial

Terraforming AI Workflows: RAG With MongoDB Atlas and Spring AI


Nov 18, 2024 | 11 min read
Tutorial

Introduction to Data Pagination With Quarkus and MongoDB: A Comprehensive Tutorial


Apr 25, 2024 | 7 min read
Article

Java 21: Unlocking the Power of the MongoDB Java Driver With Virtual Threads


Jan 31, 2024 | 2 min read
Table of Contents