Press ESC to close

Implementing Complex Authentication Scenarios in Microsoft Graph

In this blog post, I will explore with you some of the complex authentication scenarios that developers may encounter when using Microsoft Graph, and how to implement them using the Microsoft Graph SDKs and the Microsoft Authentication Library (MSAL) for various platforms. I will cover the following topics:

  • What is MSAL and how does it work with Microsoft Graph?
  • How to use MSAL to acquire tokens for Microsoft Graph?
  • How to handle conditional access policies and multi-factor authentication?
  • How to use MSAL to implement single sign-on (SSO) and single sign-out (SSO) across multiple applications?
  • How to use MSAL to implement device code flow and integrated Windows authentication?
  • How to use MSAL to implement on-behalf-of flow and client credentials flow?

What is MSAL and how does it work with Microsoft Graph?

MSAL is a set of libraries that enable developers to acquire tokens from the Microsoft identity platform endpoint in order to access secured resources such as Microsoft Graph. MSAL abstracts the complexity of authentication protocols and provides a consistent interface across different platforms and languages. MSAL supports various authentication flows, such as interactive, silent, device code, integrated Windows authentication, on-behalf-of, and client credentials.

MSAL works with Microsoft Graph by leveraging the OAuth 2.0 and OpenID Connect protocols, which are the industry standards for securing web APIs and web applications. MSAL helps developers to obtain access tokens and refresh tokens from the Microsoft identity platform endpoint, and use them to call Microsoft Graph API endpoints. MSAL also handles token caching, token renewal, and token validation.

MSAL is available for various platforms and languages, such as .NET, Java, Python, and JavaScript. MSAL is also integrated with the Microsoft Graph SDKs, which are wrappers around the Microsoft Graph API that provide a fluent and easy-to-use interface for developers. The Microsoft Graph SDKs handle the authentication process by using MSAL internally, and allow developers to focus on the business logic of their applications.

How to use MSAL to acquire tokens for Microsoft Graph?

The basic steps to use MSAL to acquire tokens for Microsoft Graph are as follows:

  1. Create an application registration in the Azure portal, and configure the required permissions and settings for Microsoft Graph. You can follow the Microsoft article to know how to register app in Azure portal. https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app 
  2. Install the MSAL library and the Microsoft Graph SDK for your platform and language of choice.
  3. Initialize an MSAL client application object with the application ID, authority, and redirect URI of your application registration.
  4. Use the MSAL client application object to acquire tokens for Microsoft Graph, either interactively or silently, depending on the authentication flow and the user context.
  5. Use the access token to call the Microsoft Graph SDK methods, or directly call the Microsoft Graph API endpoints.

.NET

				
					// Install the Microsoft.Identity.Client and Microsoft.Graph NuGet packages
using Microsoft.Identity.Client;
using Microsoft.Graph;
// Create an MSAL client application object
var app = PublicClientApplicationBuilder.Create("your-application-id")
.WithAuthority("https://login.microsoftonline.com/your-tenant-id")
.WithRedirectUri("https://localhost")
.Build();
// Acquire an access token interactively
var scopes = new[] { "user.read", "mail.read" };
var result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
// Use the access token to call the Microsoft Graph SDK
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(request =>
{
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", result.AccessToken);
return Task.CompletedTask;
}));
var user = await graphClient.Me.Request().GetAsync();
var messages = await graphClient.Me.MailFolders.Inbox.Messages.Request().GetAsync();

				
			

Java

				
					// Install the msal4j and microsoft-graph libraries
import com.microsoft.aad.msal4j.*;
import com.microsoft.graph.authentication.*;
import com.microsoft.graph.models.*;
import com.microsoft.graph.requests.*;
// Create an MSAL client application object
PublicClientApplication app = PublicClientApplication.builder("your-application-id")
.authority("https://login.microsoftonline.com/your-tenant-id")
.build();
// Acquire an access token interactively
Set<String> scopes = Collections.singleton("user.read mail.read");
InteractiveRequestParameters parameters = InteractiveRequestParameters
.builder(new URI("http://localhost"))
.scopes(scopes)
.build();
IAuthenticationResult result = app.acquireToken(parameters).get();
// Use the access token to call the Microsoft Graph SDK
IAuthenticationProvider authProvider = new TokenCredentialAuthProvider(scopes,
new StaticTokenCredential(result.accessToken()));
GraphServiceClient graphClient = GraphServiceClient.builder()
.authenticationProvider(authProvider)
.buildClient();
User user = graphClient.me().buildRequest().get();
IMailFolderCollectionPage messages = graphClient.me().mailFolders("Inbox").messages()
.buildRequest().get();

				
			

Python

				
					# Install the msal and msgraph-sdk-python-core libraries
import msal
import msgraphcore
# Create an MSAL client application object
app = msal.PublicClientApplication("your-application-id",
authority="https://login.microsoftonline.com/your-tenant-id")
# Acquire an access token interactively
scopes = ["user.read", "mail.read"]
result = app.acquire_token_interactive(scopes)
# Use the access token to call the Microsoft Graph SDK
middleware = msgraphcore.AuthProvider(auth_session_type=None,
token=result["access_token"])
graph_client = msgraphcore.GraphSession(middleware)
user = graph_client.get("/me")
messages = graph_client.get("/me/mailfolders/inbox/messages")

				
			

JavaScript

				
					// Install the msal and @microsoft/microsoft-graph-client libraries
import * as msal from "msal";
import { Client } from "@microsoft/microsoft-graph-client";
// Create an MSAL client application object
const app = new msal.PublicClientApplication({
auth: {
clientId: "your-application-id",
authority: "https://login.microsoftonline.com/your-tenant-id",
redirectUri: "http://localhost",
},
});
// Acquire an access token interactively
const scopes = ["user.read", "mail.read"];
const loginRequest = { scopes };
app.loginPopup(loginRequest).then((result) => {
// Use the access token to call the Microsoft Graph SDK
const client = Client.init({
authProvider: (done) => {
done(null, result.accessToken);
},
});
client.api("/me").get().then((user) => {
console.log(user);
});
client.api("/me/mailfolders/inbox/messages").get().then((messages) => {
console.log(messages);
});
});

				
			

How to handle conditional access policies and multi-factor authentication?

Conditional access policies are rules that define the conditions under which users or applications can access certain resources, such as Microsoft Graph. For example, a conditional access policy may require that users perform multi-factor authentication (MFA) when accessing Microsoft Graph from outside the corporate network, or that applications use a certificate to authenticate when accessing Microsoft Graph on behalf of a user.

MSAL supports handling conditional access policies and MFA by providing mechanisms to handle various error scenarios and prompts. For example, MSAL can handle the following situations:

  • The user needs to perform an additional step of authentication, such as entering a verification code or approving a notification on their mobile device.
  • The user needs to consent to the permissions requested by the application.
  • The user needs to change their password or update their account information.
  • The application needs to provide a proof of possession of a key, such as a certificate or a thumbprint.

The way MSAL handles these situations depends on the platform and the authentication flow. For interactive flows, such as interactive and device code, MSAL will either prompt the user to perform the required action, or throw an exception with a specific error code and message that indicates the action needed. For silent flows, such as silent and on-behalf-of, MSAL will throw an exception with a specific error code and message that indicates the action needed, and optionally provide a suggested action, such as invoking an interactive flow or providing a certificate.

The following code snippets show how to handle conditional access policies and MFA in different platforms and languages. Note that these are simplified examples for illustration purposes, and you may need to modify them according to your specific scenario and requirements.

				
					// Handle conditional access and MFA for interactive flow
try
{
var result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
// Use the access token
}
catch (MsalUiRequiredException ex)
{
// This exception is thrown when an interactive action is required
switch (ex.ErrorCode)
{
case "invalid_grant":
// This error code is returned when the user needs to perform an additional step of authentication
// Invoke an interactive flow with the same parameters as before
result = await app.AcquireTokenInteractive(scopes)
.WithPrompt(Prompt.SelectAccount)
.ExecuteAsync();
// Use the access token
break;
case "consent_required":
// This error code is returned when the user needs to consent to the permissions requested by the application
// Invoke an interactive flow with the same parameters as before, but with a prompt for consent
result = await app.AcquireTokenInteractive(scopes)
.WithPrompt(Prompt.Consent)
.ExecuteAsync();
// Use the access token
break;
case "interaction_required":
// This error code is returned when the user needs to change their password or update their account information
// Invoke an interactive flow with the same parameters as before, but with a prompt for interaction
result = await app.AcquireTokenInteractive(scopes)
.WithPrompt(Prompt.ForceLogin)
.ExecuteAsync();
// Use the access token
break;
default:
// Handle other error codes
break;
}
}
catch (MsalException ex)
{
// Handle other exceptions
}
// Handle conditional access and MFA for silent flow
try
{
var result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync();
// Use the access token
}
catch (MsalUiRequiredException ex)

				
			

Rezwanur Rahman

Rezwanur Rahman is the Microsoft Graph MVP, located in Innsbruck, Austria. He is the ex-Microsoft employee at Microsoft Bangladesh, and Microsoft Technical Support Lead for Microsoft 365 Global Support. He is a software engineer graduate and currently contributing technical knowledge on Microsoft Copilot and ChatGPT.