Use Azure AD to log in with Microsoft Account in Spring
In many situations, you want to allow users to login into your application using an existing account from another provider, like Google or Microsoft. This way you don’t have to add more complexity and security risks to your web app since the password is not stored on your server. You will only need to store the email and maybe some personal details, however, the password is stored on the provider’s servers and you won’t have to deal with registration or forgot password flows.
Furthermore, these providers usually offer a way to use their infrastructure to store the credentials. For example, Microsoft has Azure Active Directory that can do all this (and much more). Not only can you use it for user authentication, but you can even use it for assigning privileges and roles if you so desire. Furthermore, you can allow users to use their existing Microsoft account to log into your Spring webapp.
So let’s look at how to use Spring and Microsoft Azure Active Directory to allow a “Login with Microsoft Account” in your web application.
Configuring Azure AD
The first thing that we need to do is to configure our Azure Active Directory. For this, you will need an Azure account, but don’t be afraid because the process is easy and free. Once you have your Azure account, create a new Azure Active Directory service. Once this is done, head over to App Registration
and create a new one.

Now we have an important setting. Azure AD can be used to allow login only with users from within your organization, or two allow users from other organizations, or to allow with personal Microsoft accounts as well. There is also a 4th option where you only allow personal accounts, however, I would recommend you choose the third since you may need to allow special users as well, users for which you can assign roles.
Once this is done, head over to your newly created App Registration
and go to Certificates and Secrets
and create a new client secret. We will be needing this one later in our development, so make sure you copy it somewhere for later use.

Next, we need to configure how our Authentication mechanism will work. To do this, head over to Authentication
and add a new platform

We will be using Web as the platform and for the redirect URL we need to specify Spring’s oAuth2 redirect URI, in this case http://localhost:8080/login/oauth2/code/
. Keep in mind that this should be changed for deployments to the actual domain name. For this article we will be running our application on localhost only, so we have localhost for the redirect URL.
On Microsoft’s Developer Website you can find more details on how to configure your Azure AD, how to add users and how to assign roles. We won’t be covering that in this article.
Integrating Azure AD into Spring
Now comes the part you are actually interested in. How to use Azure Active Directory with your Spring application. If you don’t already have a Spring app, you can use Spring Initializer to create one. Make sure you add Azure Active Directory
as a dependency. If you already have a Spring app, add the following dependencies:
ext {
set('springCloudAzureVersion', "4.4.1")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.azure.spring:spring-cloud-azure-starter-active-directory'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "com.azure.spring:spring-cloud-azure-dependencies:${springCloudAzureVersion}"
}
}
For this tutorial, we will have three endpoints. One endpoint that can only be accessed by Administrators, a role we added in our Azure AD. Another endpoint that can be accessed by any user that is logged in with a Microsoft account and finally an endpoint that is publicly available, even without authentication.
When the two endpoints that require authentication are accessed we want Spring to automatically redirect non-logged-in users to the Microsoft authentication page. To do this we need to configure Spring Security. For this, let’s create a SecurityConfig
class that extends WebSecurityConfigurerAdapter
. Here we can write our rules.
SecurityConfig.java@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/admin").authenticated().and().oauth2Login(); http.authorizeRequests().antMatchers("/user").authenticated().and().oauth2Login(); http.authorizeRequests().antMatchers("/**").permitAll(); } }
As a note, when this article was written Azure Cloud library for Spring still used the deprecated WebSecurityConfigurerAdapter
class. Since this does not work with the newer filter chain method, we are forced to use it as well.
Now let’s create a simple controller with these three endpoints. We will add the authorization annotations later. For now, let’s just focus on logging in with Azure AD.
HelloController.java@RestController public class HelloController { @GetMapping("/admin") @ResponseBody public String admin() { return "Admin message"; } @GetMapping("/user") @ResponseBody public String user() { return "User message"; } @GetMapping("/all") public String publicEndpoint() { return "This is public"; } }
Last thing we need to do is configure our connection to the Active Directory. For this, we will need three important values: the tenant ID, the application ID and the client secret. The secret I asked you to copy it somewhere earlier. The other two can be obtained from your Azure account, under App Registration
.

These values need to be added to your application.properties
or another configuration file you have in your application like so:
application.properties# Enable related features. spring.cloud.azure.active-directory.enabled=true # Specifies your Active Directory ID: spring.cloud.azure.active-directory.profile.tenant-id=4afdec90-d0f6-4xxxxxxxxxxxxx # Specifies your App Registration's Application ID: spring.cloud.azure.active-directory.credential.client-id=e40eeb12-9fea-4xxxxxxxxxxxxxx # Specifies your App Registration's secret key: spring.cloud.azure.active-directory.credential.client-secret=NDp8Q~QoQgrxxxxxxxxxxxxxxxxxx
Now you can start your application. When you try to access any of the two protected endpoints you will be redirected to Microsoft’s account login page. If you use the same email as the one you used to create your azure account everything will be fine and login will work.
Public Microsoft Accounts not working
However, if you use another public Microsoft account, you will be greeted with an error: User account from identity provider live.com does not exist in tenant and cannot access the application in that tenant. The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.

Why is this happening? We have our Azure AD configured to allow public Microsoft accounts. Everything should be working correctly, however, it is not. This is something that confused me at first as well, and Microsoft’s documentation does not offer much help.
The problem is in the way Microsoft’s API works and it is not clearly explained. When you configure a tenant ID in your application, login requests will go directly to that tenant. This tenant does not know about the public account and even though it allows login, it does not consider it a valid user. For logging in with public Microsofts accounts in a multi-tenant app, you need to call the /common
endpoint.
We do not control the endpoint in this scenario directly, however, it is built based on the tenant ID provided in the configuration file. All we need to do is replace our own tenant ID with the common
keyword. Now login redirects will go to the right tenant.
application.properties# Enable related features. spring.cloud.azure.active-directory.enabled=true # Specifies your Active Directory ID: spring.cloud.azure.active-directory.profile.tenant-id=common # Specifies your App Registration's Application ID: spring.cloud.azure.active-directory.credential.client-id=e40eeb12-9fea-4xxxxxxxxxxxxxx # Specifies your App Registration's secret key: spring.cloud.azure.active-directory.credential.client-secret=NDp8Q~QoQgrxxxxxxxxxxxxxxxxxx

Authorizing with Spring Security and Azure Active Directory
We managed to authenticate using Azure Active Directory and we have the security context properly set. The last thing we need to do is authorize the user. Authorization is actually verifying if the logged-in user has access to a resource or not. Currently we don’t have any such check and even though the /admin
and /user
endpoints require authentication, it does not check any roles.
Let’s fix that. We have two types of users. User which are from within our Azure tenant and can be found in our Active Directory instance, and users that are using their public Microsoft account, those that could have only loggedin after we made the change to the common
tenant.
For internal users we need to define a new App Role
. This is done under App Registration
> App Roles
. Here, let’s create a new Admin app role:

Now we can authorize users that have this role assigned. To do this, we need to ad the @PreAuthorize
annotation. Inside we need to tell Spring Security to check if the user has the required authority. Authorities have the structure APPROLE_XXX
, where XXX
replaces the value of our role. In this case, it is @PreAuthorize("hasAuthority('APPROLE_Admin')")
.
For user that are not internal, aka users that used their own Microsoft account, the authority is ROLE_USER
. So, for the /user
endpoint, we need to add @PreAuthorize("hasAuthority('ROLE_USER')")
. Standard usage for Spring Security apply, and you can specify multiple authorities if needed. If you already use Spring Security in your application you may already have roles defined and you know how to do these types of checks.
After the latest changes, our controller looks like this:
HelloController.java@RestController public class HelloController { @GetMapping("/admin") @ResponseBody @PreAuthorize("hasAuthority('APPROLE_Admin')") public String admin() { return "Admin message"; } @GetMapping("/user") @ResponseBody @PreAuthorize("hasAuthority('ROLE_USER')") public String user() { return "User message"; } @GetMapping("/all") public String publicEndpoint() { return "This is public"; } }
Download full source code below: