Skip to content

Client credential flows 2x

Peter edited this page Oct 19, 2023 · 4 revisions

This page is for an older MSAL.NET version. See Client credential flows in MSAL.NET for updated documentation.

Client credential flows in MSAL.NET 2.x

This article is for MSAL.NET 3.x. If you are interested in MSAL.NET 3.x, please visit Client credential flows in MSAL.NET

Availability by platform

MSAL is a multi-framework library. All Confidential Client flows, including the one presented here, are available on:

  • .NET Core
  • .NET Desktop
  • .NET Standard

They are not available on the mobile platforms, because the OAuth2 spec states that there should be a secure, dedicated connection between the application and the Identity Provider. This secure connection can be achieved on web app or web API back-ends by deploying a certificate. It's also possible to use secret string, even if this alternative is not recommended for production. However, it cannot be achieved on mobile and other client applications that are distributed to users. As such, these flows are not available on:

  • Xamarin.Android
  • Xamarin.iOS
  • UWP

Overview of MSAL.NET public API for client credentials

MSAL.NET supports three types of client credentials:

  • Application secrets
  • Certificates
  • Optimized client assertions

These client credentials need to be:

  • registered with Azure AD
  • Passed in the constructors of ConfidentialClientApplication in your code

Then you can call AcquireTokenForClientAsync.

Registration of application secret or certificate with Azure AD

You can register your application secrets either through the interactive experience in the Azure portal, or using command-line tools (like PowerShell)

Registering client secrets using the application registration portal

The management of client credentials happens in the certificates & secrets page for an application:

image

  • the application secret (also named client secret) is generated by Azure AD during the registration of the confidential client application when you select New client secret. At that point, you must copy the secret string in the clipboard for use in your app, before selecting Save. This string won't be presented any longer.
  • the certificate is uploaded in the application registration using the Upload certificate button

Registering client secrets using PowerShell

The active-directory-dotnetcore-daemon-v2 sample shows how to register an application secret or a certificate with an Azure AD application:

Construction of ConfidentialClientApplication with client credentials

In MSAL client credentials are similar to what they are in ADAL.NET, except that the Client Credentials are passed as a parameter of both ConfidentialClientApplication constructors.

Then, once the confidential client application is constructed, acquiring the token is a question of calling overrides of AcquireTokenForClientAsync, passing the scope, and forcing or not a refresh of the token.

image

The ClientAssertionCertificate class passed as an argument to the ConfidentialClientApplication constructors is similar to the ADAL.NET one, however, in this case, the ClientAssertionCertificate is a Client Assertion like the application secret.

image

Unsurprisingly, the ClientAssertionCertificate is instantiated passing a X509Certificate2 instance.

image

Code snippet

The following code snippet shows how to acquire a token to call the Microsoft Graph. It uses the application permissions that were statically registered for the application. A client secret or a certificate is used depending whether the VariationWithCertificateCredentials constant is defined or not. config.ClientSecret and config.CertificateName are both strings. For more information, see AuthenticationConfig.cs

// Even if this is a console application here, a daemon application is a confidential client application
ClientCredential clientCredentials;

#if !VariationWithCertificateCredentials
// Building the client credentials from a client secret (secret string)
clientCredentials = new ClientCredential(config.ClientSecret);
#else
// Building the client credentials from a certificate
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
clientCredentials = new ClientCredential(new ClientAssertionCertificate(certificate));
#endif
var app = new ConfidentialClientApplication(config.ClientId, config.Authority, "https://daemon",
                                            clientCredentials, null, new TokenCache());

// With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the
// application permissions need to be set statically (in the portal or by PowerShell), and then granted by
// a tenant administrator
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };

AuthenticationResult result = null;
try
{
 result = await app.AcquireTokenForClientAsync(scopes);
}
catch(MsalServiceException ex)
{
 // Case when ex.Message contains:
 // AADSTS70011 Invalid scope. The scope has to be of the form "https://resourceUrl/.default"
 // Mitigation: change the scope to be as expected
}

Remarks

AcquireTokenForClientAsync uses the application token cache

AcquireTokenForClientAsync uses the application token cache (not the user token cache). The application token cache is the second token cache passed in the constructor of ConfidentialClientApplication. Don't call AcquireTokenSilentAsync before calling AcquireTokenForClientAsync as AcquireTokenSilentAsync uses the user token cache. AcquireTokenForClientAsync checks the application token cache itself and updates it.

Scopes to request

The scope to request for a client credential flow is the name of the resource followed by /.default. This notation tells Azure AD to use the application level permissions declared statically during the application registration. Also these API permissions must be granted by a tenant administrator

ResourceId = "someAppIDURI";
var scopes = new [] {  ResourceId+"/.default"};

var result = app.AcquireTokenForClientAsync(scopes);

The Reply URL passed in the constructor is not used

In the case where your confidential client application uses only client credentials flow, the reply URL passed in the constructor can be anything except null. It's not used. (In the future, null would be allowed: See issue #426)

Samples illustrating acquiring tokens interactively with MSAL.NET

Sample Platform Description
active-directory-dotnetcore-daemon-v2 .NET Core 2.1 Console topology A simple .NET Core application that displays the users of a tenant querying the Microsoft Graph using the identity of the application, instead of on behalf of a user. topology The sample also illustrates the variation with certificates
active-directory-dotnet-daemon-v2 ASP.NET MVC topologyA web application that sync's data from the Microsoft Graph using the identity of the application, instead of on behalf of a user.

More info

You can find more information in:

Vanity URL: https://aka.ms/msal-net-client-credentials

Getting started with MSAL.NET

Acquiring tokens

Desktop/Mobile apps

Web Apps / Web APIs / daemon apps

Advanced topics

News

FAQ

Other resources

Clone this wiki locally