Here we will demonstrate how to connect Azure AD and Cognito so existing Cognito users can easily sign into and use a Spring web app running on Azure.
Enterprises are increasingly adopting a multi-cloud strategy to benefit from increased speed, easier management, and lower costs. Still, this strategy requires an integrated solution to deliver a unified experience rather than isolated services. Microsoft Azure Active Directory (AD) handles the more challenging aspects of authentication and authorization in a multi-cloud environment while you focus on other aspects of your application.
This article demonstrates integrating the Amazon Web Services (AWS) Cognito user identity service with the Azure authentication service in a Spring Boot application. The solution enables users of either identity service to access the application.
To follow along with this tutorial, you must have:
We built the guestBook application using Spring Boot, Spring MVC, and Thymeleaf frameworks. Previously, the application was a part of an on-premises AD authentication. In the second article of this series, we enabled social logins for our application. We now configure the same application to integrate the Microsoft platform log-in process.
Setting up AWS Cognito
Amazon Cognito provides secure user authentication, authorization, and user management for web and mobile applications. The service offers the following types of solutions:
- The User Pool service provides sign-up and sign-in options for app users.
- The Identity Pool service grants them access to other AWS services.
Let’s start by creating a new user pool that we can use to authenticate users for the guestBook application. We provide the pool name, then click Review defaults.
This action brings us to the final step.
The detailed workflow presents opportunities to customize the user pool’s behavior according to business requirements. Investigate the Cognito documentation to learn more details about these attributes.
Adding Users
Now that we have the user pool, we must add a few users to authenticate. The AWS Cognito service provides a management console to add users, but the console does not provide the capability to add user attributes like a name.
Alternatively, the AWS command-line interface (CLI) provides commands to add or update users along with their attribute information. Refer to the CLI documentation to install it.
Post-install, we must configure the CLI with our AWS account’s credentials.
$ aws configure
Now we can add the user using the cognito-idp
command with the admin-create-user
subcommand, demonstrated below. Be sure to substitute the pool-id
with the correct ID.
$ aws cognito-idp admin-create-user --user-pool-id us-east-2_XXXX --username gsguest --user-attributes Name="given_name",Value="GS" --user-attributes Name="name",Value="GS Guest"
We can verify the user using the Cognito management console.
Adding App Clients
A client ID and secret control access to the AWS Cognito user pool. We need these credentials to integrate the Azure AD.
Add an app client by providing a suitable name.
Configuring OAuth
Cognito provides user authentication using the OAuth 2.0 framework. The framework offers the validation of details that it can share with the requesting application. We enable this validation function by selecting the supported OAuth scope. To do this, we move to the App client console to provide the app client’s required scope.
Be sure to select email, profile, and openid. Also, choose Cognito User Pool for the enabled identity provider.
Additionally, we must specify an Azure tenant-based URL to accept the validated tokens. The URL is:
https://gswebcognito.b2clogin.com/gswebcognito.onmicrosoft.com/oauth2/authresp
Be sure to replace the name with that of your Azure B2C tenant. You can perform this step later when the Azure B2C tenant is available.
Azure submits a request to the AWS Cognito pool hosted on an AWS subdomain or a custom domain to authenticate users. We must configure these details on the Domain Name Management console under App Integration.
Adding Azure Authentication
Azure AD supports integrating third-party identity providers based on OpenID Connect (OIDC). The OIDC framework uses OAuth 2.0, which delegates user authentication to a service provider that hosts the user account. Additionally, the service provider must authorize third-party applications to access the user details. In this way, OAuth 2.0 creates a single framework to secure APIs for mobile apps and browser applications in a single, cohesive architecture.
Creating a B2C Azure Active Directory
To integrate using OIDC, we need a B2C Azure AD. Before proceeding, ensure that your account has a valid subscription. Then, we can create a B2C Azure AD.
Create a new tenant by clicking Azure Active Directory > Manage tenants > Create a tenant.
New tenants appear on the Switch tenant page.
Click Switch to work with that tenant.
Next, create application credentials by moving an application page to the register and clicking New Registration. Provide a name and select Accounts in any organizational directory and personnel Microsoft accounts for the account type.
After submission, the page shows the client ID and tenant ID details.
Application credentials also require a client secret, so move to the Certificates & Secrets area of the gsWeb app. Click new secret to generate a secret for the project.
In the gsWeb application, specify the token return URL as http://localhost:8080/login/oauth2/code/. This URL is the token return path in the Java application.
If you deploy the application using a domain name, change the path accordingly. Also, select both access and ID tokens for identity exchange.
The Azure platform also enables us to validate this third-party platform integration from a browser. Validation submits a token to a JWT service, such as http://jwt.ms. The service renders the token details.
Therefore, add http://jwt.ms to the list of return URLs.
Integrating OIDC
The Azure platform enables us to integrate various identity providers for user authentication. It has out-of-the-box connectors for popular social services and interfaces with any identity service that supports OIDC. Since we enable login using AWS Cognito in this application, we must create an OIDC provider.
The provider asks for the following details:
- Name: can be any logical name.
- Metadata URL: provides details about the OIDC service. AWS Cognito provides the URL for every user pool in the format: https://cognito-idp.ZONE.amazonaws.com/COGNITO_POOL_ID/.well-known/openid-configuration. Make sure to replace the zone and Cognito pool ID details.
- Client ID: the client ID generated for AWS Cognito App clients.
- Client secret: the secret generated for AWS Cognito App clients.
- Scope: should be OpenID email profile.
- Domain: the domain mapping created for AWS Cognito.
- Claim mappings: the mapping of details that OpenID provides. OpenID maps the user ID to
sub
, Display name to name
, Given name to given_name
, and Family name to surname
.
Creating User Flows
After creating the identity provider, you must enable the application-specific data flow. In the gsWeb app, you only need the sign-up and sign-in flow, so click user flows and create a flow using the recommended configuration. The dialog asks for the following additional details:
- Name: a logical name for the flow.
- Accounts: select None to disallow any users created in the AD.
- Identity providers: select the newly-added OIDC provider.
- User Attributes: be sure to select the Return claim check box for Given Name as the attribute is in the token returned to the application.
Verifying the Integration
As discussed before, the Azure platform enables us to validate the integrations.
To do so, open the newly-created user flow. The platform presents an option to run the flow. That action opens a dialog to select the return URL. Select the application and the http://jwt.ms URL that we added to the app return URLs.
Click Run. Then, the browser opens a dialog box to provide credentials for the AWS Cognito user accounts.
Integrating the Application
Now that we have validated the Azure AD configuration, all that remains is integrating the guestBook application with the AD. To configure authentication in the application, we must add dependencies for the Azure AD B2C.
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>azure-spring-boot-starter-active-directory-b2c</artifactId>
<version>3.9.0</version>
</dependency>
The Spring Boot starter requires the following additional parameters to connect to the correct Azure AD:
Base-URI
: every B2C AD has a base URL that identifies the AD. Client-id
: the client ID that the Azure AD application registration generates. Client-secret
: the client secret associated with the Azure AD application registration. User-flows
: the name of the user flow created in Azure AD.
You must provide the aforementioned parameters as part of the application.properties in the src/main/resources folder like this:
# Azure AD properties
azure.activedirectory.b2c.base-uri: https://gswebcognito.b2clogin.com/gswebcognito.onmicrosoft.com/
azure.activedirectory.b2c.client-id: e545f841-3c93-4944-976e-32bff5b9baa2
azure.activedirectory.b2c.client-secret: XXXXX~1pAB9gwWyz7XXXXXXXXXXXXXX
azure.activedirectory.b2c.user-flows.sign-up-or-sign-in: B2C_1_cognito
Getting User Details
We must enable authentication by using security annotation EnableWebSecurity
. Moreover, it is preferable to apply the annotation to a SecurityConfig
class. The class allows us to customize and fine-tune security for our application needs.
@EnableWebSecurity
public class AADOAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
private final AADB2COidcLoginConfigurer configurer;
public AADOAuth2LoginSecurityConfig(AADB2COidcLoginConfigurer configurer) {
this.configurer = configurer;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.apply(configurer)
;
}
}
The above integration generates OAuth2AuthenticationToken
, which can read OAuth2 details. This configuration is enabled for all requests. Therefore, you can modify the GET
request to read the username from the principal rather than asking the user:
@GetMapping({"/"})
public String loadBookEntry(Model model, OAuth2AuthenticationToken principal) {
BookEntryDTO dto = new BookEntryDTO();
dto.setName(principal.getPrincipal().getAttributes().get("name").toString());
model.addAttribute("bookentry", dto);
return "bookentry";
}
Now, start the application and access its URL. The application uses Microsoft-based authentication. You can log in using your Outlook.com or Skype credentials.
Next Steps
You now know how to integrate Azure AD with the OIDC framework seamlessly. The Azure Spring Boot library provides concise integration with convention-based default values. This library eliminates the frustration associated with the integration while providing the capability to modify it as needed. Developers can focus on their business flows while leaving all boilerplate integration to Azure AD and the associated Spring Boot starter library.
You have made your application and its data more secure by requiring a login. You have also made it a seamless experience for users accessing the application in a multi-cloud environment. It’s just as straightforward to add Azure AD to an existing application as to a new one, and Azure AD plays nicely with existing enterprise authentication and single sign-on (SSO) solutions, so you can apply these methods to enhance all your applications.
Since you know how to integrate Azure AD with an on-premise AD, social logins, and AWS via OICD, you are ready to add robust authentication to your own applications, no matter their architecture, while providing a seamless user experience. Go ahead and create your exciting new Java app, deploy it to Azure, and add Azure AD authentication to secure your application’s data and provide a personalized user experience.
To learn more about the evolution of the Azure Active Directory (Azure AD), check out The Developer's Guide to Azure.