Secure your API with Spring Data MongoDB and Microsoft EntraID
Rate this tutorial
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!
- Java Development Kit (JDK) version 17 or higher
- A Spring Boot application — you can create a Maven project with the Spring Initializr; there are a couple of dependencies you will need:
- Spring Web
- OAuth2 Resource Server
- Azure Active Directory
- Select Java version 17 or higher and generate a JAR
You can follow along with this tutorial and build your project as you read or you can clone the repository directly:
1 git clone git@github.com:mongodb-developer/java-spring-boot-secure-todo-app.git
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
.1 spring.application.name=todo 2 spring.cloud.azure.active-directory.enabled=true 3 spring.cloud.azure.active-directory.profile.tenant-id=<YOUR-TENANT-ID> 4 spring.cloud.azure.active-directory.credential.client-id=<YOUR-APPLICATION-ID> 5 spring.security.oauth2.client.registration.azure.client-authentication-method=none 6 spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.microsoftonline.com/<YOUR-TENANT-ID/v2.0 7 server.forward-headers-strategy=framework 8 springdoc.swagger-ui.use-root-path=true 9 springdoc.swagger-ui.oauth.use-pkce-with-authorization-code-grant=true 10 spring.security.oauth2.client.registration.azure.redirect-uri=http:<YOUR-APPLICATION-URL>/swagger-ui/oauth2-redirect.html 11 spring.data.mongodb.uri=<YOUR-MONGODB-CONNECTION-URI> 12 spring.data.mongodb.database=<YOUR-MONGODB-DATABASE>
spring.application.name=todo
: Defines the name of your Spring Boot applicationspring.cloud.azure.active-directory...
: Integrates your application with Azure AD for authentication and authorizationspring.security.oauth2.client.registration.azure.client-authentication-method=none
: Specifies the authentication method for the OAuth2 client; setting it tonone
is used for public clients, where a client secret is not applicablespring.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 ADserver.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 redirectsspringdoc.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.1 package com.example.todo.model; 2 3 import org.springframework.data.annotation.Id; 4 import org.springframework.data.mongodb.core.mapping.Document; 5 6 7 public class Todo { 8 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.1 package com.example.todo.model.repository; 2 3 import com.example.todo.model.Todo; 4 import org.springframework.data.mongodb.repository.MongoRepository; 5 6 public 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.1 package com.example.todo.service; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import com.example.todo.model.Todo; 7 import com.example.todo.model.repository.TodoRepository; 8 9 import java.util.List; 10 import java.util.Optional; 11 12 13 public class TodoService { 14 15 private 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.
1 package com.example.todo.controller; 2 3 import com.example.todo.model.Todo; 4 import com.example.todo.sevice.TodoService; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.security.access.prepost.PreAuthorize; 8 import org.springframework.security.core.Authentication; 9 import org.springframework.web.bind.annotation.*; 10 import java.util.List; 11 12 13 14 15 public class TodoController { 16 17 public TodoController(TodoService todoService) { 18 this.todoService = todoService; 19 } 20 21 22 public List<Todo> getAllTodos() { 23 return todoService.findAll(); 24 } 25 26 27 public Todo getTodoById( String id) { 28 return todoService.findById(id).orElse(null); 29 } 30 31 32 33 public Todo createTodo( Todo todo, Authentication authentication) { 34 return todoService.save(todo); 35 } 36 37 38 39 public Todo updateTodo( String id, Todo todo) { 40 return todoService.save(todo); 41 } 42 43 44 45 public void deleteTodo( 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.1 package com.example.todo.config; 2 3 import io.swagger.v3.oas.models.Components; 4 import io.swagger.v3.oas.models.OpenAPI; 5 import io.swagger.v3.oas.models.info.Info; 6 import io.swagger.v3.oas.models.security.OAuthFlow; 7 import io.swagger.v3.oas.models.security.OAuthFlows; 8 import io.swagger.v3.oas.models.security.Scopes; 9 import io.swagger.v3.oas.models.security.SecurityScheme; 10 11 import org.springframework.beans.factory.annotation.Value; 12 import org.springframework.context.annotation.Bean; 13 import org.springframework.context.annotation.Configuration; 14 15 16 17 class OpenApiConfiguration { 18 19 20 private String tenantId; 21 22 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).1 package com.example.todo.config; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 import org.springframework.security.web.SecurityFilterChain; 7 import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; 8 9 10 11 public class WebConfig { 12 13 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.
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.
- Sign in to the Azure portal. If you have access to multiple tenants, select the tenant in which you want to register an application.
- Search for and select the Microsoft Entra ID service.
- If you don't already have one, create one here.
- From the left side menu, under Manage, select App registrations and New registration.
- 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
. - 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.
- Select Register to create the application.
- 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. - Navigate to Manage and click on Expose an API. Locate the Application ID URI at the top of the page and click Add.
- 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 likeapi://todo
before hitting Save. - 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.
- 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.
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.
We are going to register a second app in Microsoft Entra ID.
- Repeat steps 1 through 6 above, but this time, name your application
TodoClient
. - 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.
- Select API permissions and Add a permission.
- 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 yourTodoClient
application. - Select Grant admin consent for
<YOUR-TENANT-NAME>
to grant admin consent for the permissions you added.
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
.- Navigate to your Microsoft Entra ID and under Manage, choose Users.
- Click on New user and then on Create new user.
- 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.
- Click Review + create to examine your entries. Press Create to finalize the creation of the user.
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.- Access your Microsoft Entra ID tenant, and navigate to the
TodoClient
app you've registered. - 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.
- 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.
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.Now, we should be ready to test some of our secure endpoints. Send a sample post request using the Swagger UI.
If everything is authorized correctly, your data should now be in your MongoDB database.
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.