-
Notifications
You must be signed in to change notification settings - Fork 343
Acquiring tokens interactively
This article is about MSAL.NET 3.x. If you are interested in MSAL.NET 2.x go to Acquiring tokens interactively in MSAL 2.x
In MSAL.NET 3.x, the method to use to acquire a token interactively is IPublicClientApplication.AcquireTokenInteractive
The following example shows minimal code to get a token for reading the user's profile with Microsoft Graph.
string[] scopes = new string[] {"user.read"};
var app = PublicClientApplicationBuilder.Create(clientId).Build();
var accounts = await app.GetAccountsAsync();
AuthenticationResult result;
try
{
result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch(MsalUiRequiredException)
{
result = await app.AcquireTokenInteractive(scopes)
.ExecuteAsync();
}
AcquireTokenInteractive
has only one mandatory parameter scopes
, which contains an enumeration of strings which define the scopes for which a token is required. If the token is for the Microsoft Graph, the required scopes can be found in api reference of each Microsoft graph API in the section named "Permissions". For instance, to list the user's contacts, the scope "User.Read", "Contacts.Read" will need to be used. See also Microsoft Graph permissions reference.
On Android, you need to also specify the parent activity (using .WithParentActivityOrWindow
, see below) so that the token gets back to that parent activity after the interaction. If you don't specify it, an exception will be thrown when calling .ExecuteAsync()
.
Being interactive, UI is important. AcquireTokenInteractive
has one specific optional parameters enabling to specify, for platforms supporting it, the parent UI (window in Windows, Activity in Android). This parent UI is specified using .WithParentActivityOrWindow()
. The UI dialog will typically be centered on that parent. As explained above, on Android the parent activity is a mandatory parameter.
.WithParentActivityOrWindow
has a different type depending on the platform:
// Android
WithParentActivityOrWindow(Activity activity)
// net45
WithParentActivityOrWindow(IntPtr windowPtr)
WithParentActivityOrWindow(IWin32Window window)
// Mac
WithParentActivityOrWindow(NSWindow window)
// iOS
WithParentActivityOrWindow(IUIViewController viewController)
// .Net Standard (this will be on all platforms at runtime, but only on NetStandard at build time)
WithParentActivityOrWindow(object parent).
Remarks:
-
On .NET Standard, the expected
object
is anActivity
on Android, aUIViewController
on iOS, anNSWindow
on MAC, and aIWin32Window
orIntPr
on Windows. -
On Windows, you must call
AcquireTokenInteractive
from the UI thread so that the embedded browser gets the appropriate UI synchronization context. Not calling from the UI thread may cause messages to not pump properly and/or deadlock scenarios with the UI. One way of achieving this, if you are not on the UI thread is to use theDispatcher
on WPF. -
If you are using WPF, to get a window from a WPF control, you can use
WindowInteropHelper.Handle
class. The call is then, from a WPF control (this):result = await app.AcquireTokenInteractive(scopes) .WithParentActivityOrWindow(new WindowInteropHelper(this).Handle) .ExecuteAsync();
With Prompt is used to control the interactivity with the user by specifying a Prompt
The class defines the following constants:
-
SelectAccount
: will force the STS to present the account selection dialog containing accounts for which the user has a session. This is useful when applications developers want to let user choose among different identities. This is done by sendingprompt=select_account
to the identity provider. This is the default, and it does of good job of providing the best possible experience based on the available information (account, presence of a session for the user, etc ...). You should not change it unless you have good reason to do it. -
Consent
: enables the application developer to force the user be prompted for consent even if consent was granted before. This is done by sendingprompt=consent
to the identity provider. This can be used in some security focused applications where the organization governance demands that the user is presented the consent dialog each time the application is used. -
ForceLogin
: enables the application developer to have the user prompted for credentials by the service even if this would not be needed. This can be useful if Acquiring a token fails, to let the user re-sign-in. This is done by sendingprompt=login
to the identity provider. Again, we've seen it used in some security focused applications where the organization governance demands that the user re-logs-in each time they access specific parts of an application. -
Never
(for .NET 4.5 and WinRT only) will not prompt the user, but instead will try to use the cookie stored in the hidden embedded web view (See below: Web Views in MSAL.NET). This might fail, and in that caseAcquireTokenInteractive
will throw an exception to notify that a UI interaction is needed, and you'll need to use anotherPrompt
parameter. -
NoPrompt
: Won't send any prompt to the identity provider. This is actually only useful in the case of B2C edit profile policies (See B2C specifics).
Enables you to specify if you want to force the usage of an embedded web view or the system web view (when available). For more details see Usage of Web browsers
result = await app.AcquireTokenInteractive(scopes)
.WithUseEmbeddedWebView(true)
.ExecuteAsync();
This is used in an advanced scenario where you want the user to pre-consent to several resources upfront (and don't want to use the incremental consent which is normally used with MSAL.NET / the Microsoft identity platform v2.0). For details see How-to : have the user consent upfront for several resources below
var result = await app.AcquireTokenInteractive(scopesForCustomerApi)
.WithExtraScopeToConsent(scopesForVendorApi)
.ExecuteAsync();
WithCustomWebUi
is an extensibility point that allows you provide your own UI in public client applications, and to let the user go through the /Authorize endpoint of the identity provider and let them sign-in and consent. MSAL.NET will then be able to redeem the authentication code and get a token. It's for instance used in Visual Studio to have electrons applications (for instance VS Feedback) provide the web interaction, but leave it to MSAL.NET to do most of the work. You can also use it if you want to provide UI automation. Note that, in public client applications, MSAL.NET leverages the PKCE standard (RFC 7636 - Proof Key for Code Exchange by OAuth Public Clients) to ensure that security is respected: Only MSAL.NET can redeem the code.
using Microsoft.Identity.Client.Extensions;
To leverage this you need to:
-
Implement the
ICustomWebUi
interface (See here. You'll basically need to implement one methodAcquireAuthorizationCodeAsync
accepting the authorization code URL (computed by MSAL.NET), letting the user go through the interaction with the identity provider, and then returning back the URL by which the identity provider would have called your implementation back (including the authorization code). In case of issues, your implementation should throw aMsalExtensionException
exception in order to nicely cooperate with MSAL. -
In your
AcquireTokenInteractive
call you can use.WithCustomUI()
modifier passing the instance of your custom web UIresult = await app.AcquireTokenInteractive(scopes) .WithCustomWebUi(yourCustomWebUI) .ExecuteAsync();
We have rewritten our UI tests to leverage this extensibility mechanism. In case you are interested you can have a look at the SeleniumWebUI class in the MSAL.NET source code
Builder modifier | Description |
---|---|
WithAuthority (7 overrides) | Overrides the authority |
WithAdfsAuthority(string) | Overrides the authority |
WithB2CAuthority(string) | Overrides the authority |
WithAccount(IAccount) |
account (optional) of type IAccount , provides a hint to the STS about the user for which to get the token. This can be set from the Account member of a previous AuthenticationResult, or one of the elements of the collection returned by GetAccountsAsync() method of the PublicClientApplication . |
WithLoginHint(string) |
loginHint (optional) offers a hint to the STS about the user for which to get the token alternative to user. It's used like userIdentifier in ADAL. Needs to be passed the preferred_username of the IDToken (contrary to ADAL which was requiring the UPN) |
WithClaims(string) | Requests additional claims. This normally is in reaction to an MsalClaimChallengeException which has a Claim member (Conditional Access) |
WithPrompt(Prompt) | Is the way to control, in MSAL.NET, the interaction between the user and the STS to enter credentials. It's different depending on the platform (See below). Note that MSAL 3.x is taking a breaking change here. Prompt used to be named UIBehavior in MSAL 1.x and 2.x |
WithExtraQueryParameters(dictionary) | A dictionary of keys / values. |
WithExtraScopesToConsent(extraScopes) | Enables application developers to specify additional scopes for which users will pre-consent. This can be in order to avoid having them see incremental consent screens when the Web API require them. This is also indispensable in the case where you want to provide scopes for several resources. See the paragraph on getting consent for several resources below for more details. |
Note: Getting consent for several resources works for Azure AD v2.0, but not for Azure AD B2C. B2C supports only admin consent, not user consent.
The Azure AD v2.0 endpoint does not allow you to get a token for several resources at once. Therefore the scopes parameter should only contain scopes for a single resource. However, you can ensure that the user pre-consents to several resources by using the extraScopesToConsent
parameter.
For instance if you have two resources, which have 2 scopes each:
-
https://mytenant.onmicrosoft.com/customerapi
(with 2 scopescustomer.read
andcustomer.write
) -
https://mytenant.onmicrosoft.com/vendorapi
(with 2 scopesvendor.read
andvendor.write
)
you should use the .WithAdditionalPromptToConsent modifier which has the extraScopesToConsent
parameter
For instance:
string[] scopesForCustomerApi = new string[]
{
"https://mytenant.onmicrosoft.com/customerapi/customer.read",
"https://mytenant.onmicrosoft.com/customerapi/customer.write"
};
string[] scopesForVendorApi = new string[]
{
"https://mytenant.onmicrosoft.com/vendorapi/vendor.read",
"https://mytenant.onmicrosoft.com/vendorapi/vendor.write"
};
var accounts = await app.GetAccountsAsync();
var result = await app.AcquireTokenInteractive(scopesForCustomerApi)
.WithAccount(accounts.FirstOrDefault())
.WithExtraScopeToConsent(scopesForVendorApi)
.ExecuteAsync();
This will get you an access token for the first Web API. Then when you need to call the second one, you can call
AcquireTokenSilent(scopesForVendorApi, accounts.FirstOrDefault()).ExecuteAsync();
See this GitHub issue for more context.
For Microsoft personal accounts users, re-prompting for consent on each native client call to authorize is the intended behavior. Native client identity is inherently insecure, and the Microsoft identity platform chose to mitigate this insecurity for consumer services by prompting for consent each time the application is authorized.
Depending on the platforms, you will need to do a bit of extra work to use MSAL.NET. For more details on each platform, see:
Sample | Platform | Description |
---|---|---|
active-directory-dotnet-desktop-msgraph-v2 | Desktop (WPF) | Windows Desktop .NET (WPF) application calling the Microsoft Graph API. |
active-directory-dotnet-native-uwp-v2 | UWP | A Windows Universal Platform client application using msal.net, accessing the Microsoft Graph for a user authenticating with Azure AD v2.0 endpoint. |
https://github.com/Azure-Samples/active-directory-xamarin-native-v2 | Xamarin iOS, Android, UWP | A simple Xamarin Forms app showcasing how to use MSAL to authenticate MSA and Azure AD via the AADD v2.0 endpoint, and access the Microsoft Graph with the resulting token. |
https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2 | WPF, ASP.NET Core 2.0 Web API | A WPF application calling an ASP.NET Core Web API using Azure AD v2.0. |
- Home
- Why use MSAL.NET
- Is MSAL.NET right for me
- Scenarios
- Register your app with AAD
- Client applications
- Acquiring tokens
- MSAL samples
- Known Issues
- AcquireTokenInteractive
- WAM - the Windows broker
- .NET Core
- Xamarin Docs
- UWP
- Custom Browser
- Applying an AAD B2C policy
- Integrated Windows Authentication for domain or AAD joined machines
- Username / Password
- Device Code Flow for devices without a Web browser
- ADFS support
- Acquiring a token for the app
- Acquiring a token on behalf of a user in Web APIs
- Acquiring a token by authorization code in Web Apps
- High Availability
- Token cache serialization
- Logging
- Exceptions in MSAL
- Provide your own Httpclient and proxy
- Extensibility Points
- Clearing the cache
- Client Credentials Multi-Tenant guidance
- Performance perspectives
- Differences between ADAL.NET and MSAL.NET Apps
- PowerShell support
- Testing apps that use MSAL
- Experimental Features
- Proof of Possession (PoP) tokens
- Using in Azure functions
- Extract info from WWW-Authenticate headers
- SPA Authorization Code