Events
17 Mar, 23 - 21 Mar, 23
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
This article demonstrates a Java JBoss EAP app that uses OpenID Connect to sign in users and Microsoft Entra ID Application Roles (app roles) for authorization.
This application implements role-based access control (RBAC) using Microsoft Entra ID's application roles and role claims feature. Another approach is to use Microsoft Entra ID groups and group claims. Microsoft Entra ID groups and application roles aren't mutually exclusive. You can use them both to provide fine-grained access control.
You can also use RBAC with application roles and role claims to securely enforce authorization policies.
For a video that covers this scenario and this sample, see Implement authorization in your applications using app roles, security groups, scopes, and directory roles.
For more information about how the protocols work in this scenario and in other scenarios, see Authentication vs. authorization.
This application uses MSAL for Java (MSAL4J) to sign in a user and obtain an ID token from Microsoft Entra ID.
This sample first uses the MSAL for Java (MSAL4J) to sign in the user. On the home page it displays an option for the user to view the claims in their ID tokens. This application also enables the users to view a privileged admin page or a regular user page, depending on the app role they've been assigned to. The idea is to provide an example of how, within an application, access to certain functionality or pages is restricted to subsets of users depending on which role they belong to.
This kind of authorization is implemented using RBAC. With RBAC, an administrator grants permissions to roles, not to individual users or groups. The administrator can then assign roles to different users and groups to control who has access to certain content and functionality.
This sample application defines the following two Application Roles:
PrivilegedAdmin
: Authorized to access the Admins Only and the Regular Users pages.RegularUser
: Authorized to access the Regular Users page.These application roles are defined in the Azure portal in the application's registration manifest. When a user signs into the application, Microsoft Entra ID emits a roles claim for each role granted individually to the user in the form of role membership.
You can assign users and groups to roles through the Azure portal.
Note
Role claims aren't present for guest users in a tenant if the https://login.microsoftonline.com/common/
endpoint is used as the authority to sign in users. You need to sign in a user to a tenanted endpoint like https://login.microsoftonline.com/tenantid
.
The following sections show you how to set up the sample application.
To clone the sample, open a Bash window and use the following command:
git clone https://github.com/Azure-Samples/ms-identity-msal-java-samples.git
cd 3-java-servlet-web-app/3-Authorization-II/roles
Alternatively, navigate to the ms-identity-msal-java-samples repository, then download it as a .zip file and extract it to your hard drive.
Important
To avoid file path length limitations on Windows, clone or extract the repository into a directory near the root of your hard drive.
There's one project in this sample. The following sections show you how to register the app using the Azure portal.
To choose your tenant, use the following steps:
Sign in to the Azure portal.
If your account is present in more than one Microsoft Entra ID tenant, select your profile in the corner of the Azure portal, and then select Switch directory to change your session to the desired Microsoft Entra ID tenant.
First, register a new app in the Azure portal by following the instructions in Quickstart: Register an application with the Microsoft identity platform.
Then, use the following steps to complete the registration:
Navigate to the Microsoft identity platform for developers App registrations page.
Select New registration.
In the Register an application page that appears, enter the following app registration information:
In the Name section, enter a meaningful application name for display to users of the app - for example, java-servlet-webapp-roles
.
Under Supported account types, select one of the following options:
In the Redirect URI section, select Web in the combo-box and enter the following redirect URI: http://localhost:8080/msal4j-servlet-roles/auth/redirect
.
Select Register to create the application.
On the app's registration page, find and copy the Application (client) ID value to use later. You use this value in your app's configuration file or files.
Select Save to save your changes.
On the app's registration page, select Certificates & secrets on the navigation pane to open the page where you can generate secrets and upload certificates.
In the Client secrets section, select New client secret.
Type a description - for example, app secret.
Select one of the available durations: In 1 year, In 2 years, or Never Expires.
Select Add. The generated value is displayed.
Copy and save the generated value for use in later steps. You need this value for your code's configuration files. This value isn't displayed again, and you can't retrieve it by any other means. So, be sure to save it from the Azure portal before you navigate to any other screen or pane.
To define the app roles, use the following steps:
Still on the same app registration, select App roles on the navigation pane.
Select Create app role, then enter the following values:
Select Create app role, then enter the following values:
Select Apply to save your changes.
To add users to the app role defined earlier, follow the guidelines here: Assign users and groups to roles.
Use the following steps to configure the app:
Note
In the following steps, ClientID
is the same as Application ID
or AppId
.
Open the project in your IDE.
Open the authentication.properties file.
Find the string {enter-your-tenant-id-here}
. Replace the existing value with your Microsoft Entra ID tenant ID.
Find the string {enter-your-client-id-here}
and replace the existing value with the application ID or clientId
of the java-servlet-webapp-call-graph
application copied from the Azure portal.
Find the string {enter-your-client-secret-here}
and replace the existing value with the value you saved during the creation of the java-servlet-webapp-roles
app, in the Azure portal.
Find the app.roles
property and make sure the value is set to app.roles=admin PrivilegedAdmin, user RegularUser
, or substitute the names of your specific roles.
To build the sample using Maven, navigate to the directory containing the pom.xml file for the sample, and then run the following command:
mvn clean package
This command generates a .war file that you can run on various application servers.
The following sections show you how to deploy the sample to Azure App Service.
Maven Plugin for Azure App Service apps
If Maven isn't your preferred development tool, see the following similar tutorials that use other tools:
The deployment process to Azure App Service uses your Azure credentials from the Azure CLI automatically. If the Azure CLI isn't installed locally, then the Maven plugin authenticates with OAuth or device sign-in. For more information, see authentication with Maven plugins.
Use the following steps to configure the plugin:
Run the Maven command shown next to configure the deployment. This command helps you to set up the App Service operating system, Java version, and Tomcat version.
mvn com.microsoft.azure:azure-webapp-maven-plugin:2.12.0:config
For Create new run configuration, press Y, then press Enter.
For Define value for OS, press 2 for Linux, then press Enter.
For Define value for javaVersion, press 2 for Java 11, then press Enter.
For Define value for webContainer, press 1 for JBosseap7, then press Enter.
For Define value for pricingTier, press Enter to select the default P1v3 tier.
For Confirm, press Y, then press Enter.
The following example shows the output of the deployment process:
Please confirm webapp properties
AppName : msal4j-servlet-auth-1707220080695
ResourceGroup : msal4j-servlet-auth-1707220080695-rg
Region : centralus
PricingTier : P1v3
OS : Linux
Java Version: Java 11
Web server stack: JBosseap 7
Deploy to slot : false
Confirm (Y/N) [Y]:
[INFO] Saving configuration to pom.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 26.196 s
[INFO] Finished at: 2024-02-06T11:48:16Z
[INFO] ------------------------------------------------------------------------
After you've confirmed your choices, the plugin adds the plugin configuration and required settings to your project's pom.xml file to configure your app to run in Azure App Service.
The relevant portion of the pom.xml file should look similar to the following example:
<build>
<plugins>
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>>azure-webapp-maven-plugin</artifactId>
<version>x.xx.x</version>
<configuration>
<schemaVersion>v2</schemaVersion>
<resourceGroup>your-resourcegroup-name</resourceGroup>
<appName>your-app-name</appName>
...
</configuration>
</plugin>
</plugins>
</build>
You can modify the configurations for App Service directly in your pom.xml. Some common configurations are listed in the following table:
Property | Required | Description | Version |
---|---|---|---|
schemaVersion |
false | The version of the configuration schema. Supported values are v1 and v2 . |
1.5.2 |
subscriptionId |
false | The subscription ID. | 0.1.0+ |
resourceGroup |
true | The Azure resource group for your app. | 0.1.0+ |
appName |
true | The name of your app. | 0.1.0+ |
region |
false | The region in which to host your app. The default value is centralus . For valid regions, see Supported Regions. |
0.1.0+ |
pricingTier |
false | The pricing tier for your app. The default value is P1v2 for a production workload. The recommended minimum value for Java development and testing is B2 . For more information, see App Service Pricing |
0.1.0+ |
runtime |
false | The runtime environment configuration. For more information, see Configuration Details. | 0.1.0+ |
deployment |
false | The deployment configuration. For more information, see Configuration Details. | 0.1.0+ |
For the complete list of configurations, see the plugin reference documentation. All the Azure Maven plugins share a common set of configurations. For these configurations, see Common Configurations. For configurations specific to Azure App Service, see Azure app: Configuration Details.
Be sure to save aside the appName
and resourceGroup
values for later use.
When you deploy your application to App Service, your redirect URL changes to the redirect URL of your deployed app instance. Use the following steps to change these settings in your properties file:
Navigate to your app's authentication.properties file and change the value of app.homePage
to your deployed app's domain name, as shown in the following example. For example, if you chose example-domain
for your app name in the previous step, you must now use https://example-domain.azurewebsites.net
for the app.homePage
value. Be sure that you've also changed the protocol from http
to https
.
# app.homePage is by default set to dev server address and app context path on the server
# for apps deployed to azure, use https://your-sub-domain.azurewebsites.net
app.homePage=https://<your-app-name>.azurewebsites.net
After saving this file, use the following command to rebuild your app:
mvn clean package
Important
In this same authentication.properties file you have a setting for your aad.secret
. It isn't a good practice to deploy this value to App Service. Neither is it a good practice to leave this value in your code and potentially push it up to your git repository. For removing this secret value from your code, you can find more detailed guidance in the Deploy to App Service - Remove secret section. This guidance adds extra steps for pushing the secret value to Key Vault and to use Key Vault References.
Because the redirect URI changes to your deployed app to Azure App Service, you also need to change the redirect URI in your Microsoft Entra ID app registration. Use the following steps to make this change:
Navigate to the Microsoft identity platform for developers App registrations page.
Use the search box to search for your app registration - for example, java-servlet-webapp-authentication
.
Open your app registration by selecting its name.
Select Authentication from the menu.
In the Web - Redirect URIs section, select Add URI.
Fill out the URI of your app, appending /auth/redirect
- for example, https://<your-app-name>.azurewebsites.net/auth/redirect
.
Select Save.
You're now ready to deploy your app to Azure App Service. Use the following command to make sure you're signed in to your Azure environment to execute the deployment:
az login
With all the configuration ready in your pom.xml file, you can now use the following command to deploy your Java app to Azure:
mvn package azure-webapp:deploy
After deployment is completed, your application is ready at http://<your-app-name>.azurewebsites.net/
. Open the URL with your local web browser, where you should see the start page of the msal4j-servlet-auth
application.
Use the following steps to explore the sample:
/admin_only
page. Only users with app role PrivilegedAdmin
can view this page. Otherwise, an authorization failure message is displayed./regular_user
page. Only users with app role RegularUser
or PrivilegedAdmin
can view this page. Otherwise, an authorization failure message is displayed.This sample uses MSAL for Java (MSAL4J) to sign a user in and obtain an ID token that might contain the roles claim. Based on the roles claim present, the signed-in user can access none, one, or both of the protected pages, Admins Only
and Regular Users
.
If you want to replicate this sample's behavior, you can copy the pom.xml file and the contents of the helpers and authservlets folders in the src/main/java/com/microsoft/azuresamples/msal4j folder. You also need the authentication.properties file. These classes and files contain generic code that you can use in a wide array of applications. You can copy the rest of the sample as well, but the other classes and files are built specifically to address this sample's objective.
The following table shows the contents of the sample project folder:
File/folder | Description |
---|---|
src/main/java/com/microsoft/azuresamples/msal4j/roles/ | This directory contains the classes that define the app's backend business logic. |
src/main/java/com/microsoft/azuresamples/msal4j/authservlets/ | This directory contains the classes that are used for sign in and sign out endpoints. |
*Servlet.java | All of the endpoints available are defined in Java classes with names ending in Servlet . |
src/main/java/com/microsoft/azuresamples/msal4j/helpers/ | Helper classes for authentication. |
AuthenticationFilter.java | Redirects unauthenticated requests to protected endpoints to a 401 page. |
src/main/resources/authentication.properties | Microsoft Entra ID and program configuration. |
src/main/webapp/ | This directory contains the UI - JSP templates |
CHANGELOG.md | List of changes to the sample. |
CONTRIBUTING.md | Guidelines for contributing to the sample. |
LICENSE | The license for the sample. |
The roles claim of the token includes the names of the roles that the signed-in user is assigned to, as shown in the following example:
{
...
"roles": [
"Role1",
"Role2",]
...
}
A ConfidentialClientApplication
instance is created in the AuthHelper.java file, as shown in the following example. This object helps craft the Microsoft Entra authorization URL and also helps exchange the authentication token for an access token.
// getConfidentialClientInstance method
IClientSecret secret = ClientCredentialFactory.createFromSecret(SECRET);
confClientInstance = ConfidentialClientApplication
.builder(CLIENT_ID, secret)
.authority(AUTHORITY)
.build();
The following parameters are used for instantiation:
In this sample, these values are read from the authentication.properties file using a properties reader in the Config.java file.
The following steps provide a walkthrough of the app's functionality:
The first step of the sign-in process is to send a request to the /authorize
endpoint on for your Microsoft Entra ID tenant. The MSAL4J ConfidentialClientApplication
instance is used to construct an authorization request URL. The app redirects the browser to this URL, which is where the user signs in.
final ConfidentialClientApplication client = getConfidentialClientInstance();
AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters.builder(Config.REDIRECT_URI, Collections.singleton(Config.SCOPES))
.responseMode(ResponseMode.QUERY).prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
final String authorizeUrl = client.getAuthorizationRequestUrl(parameters).toString();
contextAdapter.redirectUser(authorizeUrl);
The following list describes the features of this code:
AuthorizationRequestUrlParameters
: Parameters that must be set in order to build an AuthorizationRequestUrl.REDIRECT_URI
: Where Microsoft Entra ID redirects the browser - along with the auth code - after collecting user credentials. It must match the redirect URI in the Microsoft Entra ID app registration in the Azure portal.SCOPES
: Scopes are permissions requested by the application.
openid profile offline_access
suffice for receiving an ID token response.User.Read
.The user is presented with a sign-in prompt by Microsoft Entra ID. If the sign-in attempt is successful, the user's browser is redirected to the app's redirect endpoint. A valid request to this endpoint contains an authorization code.
The ConfidentialClientApplication
instance then exchanges this authorization code for an ID token and access token from Microsoft Entra ID.
// First, validate the state, then parse any error codes in response, then extract the authCode. Then:
// build the auth code params:
final AuthorizationCodeParameters authParams = AuthorizationCodeParameters
.builder(authCode, new URI(Config.REDIRECT_URI)).scopes(Collections.singleton(Config.SCOPES)).build();
// Get a client instance and leverage it to acquire the token:
final ConfidentialClientApplication client = AuthHelper.getConfidentialClientInstance();
final IAuthenticationResult result = client.acquireToken(authParams).get();
The following list describes the features of this code:
AuthorizationCodeParameters
: Parameters that must be set in order to exchange the Authorization Code for an ID and/or access token.authCode
: The authorization code that was received at the redirect endpoint.REDIRECT_URI
: The redirect URI used in the previous step must be passed again.SCOPES
: The scopes used in the previous step must be passed again.If acquireToken
is successful, the token claims are extracted. If the nonce check passes, the results are placed in context
- an instance of IdentityContextData
- and saved to the session. The application can then instantiate the IdentityContextData
from the session by way of an instance of IdentityContextAdapterServlet
whenever it needs access to it, as shown in the following code:
// parse IdToken claims from the IAuthenticationResult:
// (the next step - validateNonce - requires parsed claims)
context.setIdTokenClaims(result.idToken());
// if nonce is invalid, stop immediately! this could be a token replay!
// if validation fails, throws exception and cancels auth:
validateNonce(context);
// set user to authenticated:
context.setAuthResult(result, client.tokenCache().serialize());
For information about how the sample app filters access to routes, see AuthenticationFilter.java. In the authentication.properties file, the app.protect.authenticated
property contains the comma-separated routes that only authenticated users can access, as shown in the following example:
# for example, /token_details requires any user to be signed in and does not require special roles claim(s)
app.protect.authenticated=/token_details
Any of the routes listed in the comma-separated rule sets under the app.protect.roles
are also off-limits to non-authenticated authenticated users, as shown in the following example. However, these routes also contain a space-separated list of app role memberships: only users having at least one of the corresponding roles can access these routes after authenticating.
# local short names for app roles - for example, sets admin to mean PrivilegedAdmin (useful for long rule sets defined in the next key, app.protect.roles)
app.roles=admin PrivilegedAdmin, user RegularUser
# A route and its corresponding <space-separated> role(s) that can access it; the start of the next route & its role(s) is delimited by a <comma-and-space-separator>
# this says: /admins_only can be accessed by PrivilegedAdmin, /regular_user can be accessed by PrivilegedAdmin role and the RegularUser role
app.protect.roles=/admin_only admin, /regular_user admin user
Scopes tell Microsoft Entra ID the level of access that the application is requesting.
Based on the requested scopes, Microsoft Entra ID presents a consent dialogue to the user upon sign-in. If the user consents to one or more scopes and obtains a token, the scopes-consented-to are encoded into the resulting access_token
.
For the scopes requested by the application, see authentication.properties. These three scopes are requested by MSAL and given by Microsoft Entra ID by default.
Events
17 Mar, 23 - 21 Mar, 23
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowTraining
Module
Sign in users with Microsoft Entra ID in a Java web app - Training
Learn how to authenticate users with Microsoft Entra ID and get authorized access to data in a Java web app using Microsoft Authentication Library.
Certification
Microsoft Certified: Identity and Access Administrator Associate - Certifications
Demonstrate the features of Microsoft Entra ID to modernize identity solutions, implement hybrid solutions, and implement identity governance.
Documentation
Enable sign-in for JBoss EAP apps using Microsoft Entra ID - Azure
Shows you how to develop a Java JBoss EAP app that supports sign-in using a Microsoft Entra account.
Secure Java apps using the Microsoft identity platform - Azure
Provides an overview of recommended strategies for securing Java applications with the Microsoft identity platform.
Enable sign-in for Java JBoss EAP apps using MSAL4J - Azure Active Directory B2C
Shows you how to develop a Java JBoss EAP app that supports sign-in by Azure Active Directory B2C.