Skip to content

Commit 71bee19

Browse files
authored
Merge pull request #114125 from mmacy/msid-issue-53783-missing-from-token-cache
[msid] clarify 'Missing from token cache' (MicrosoftDocs/azure-docs#53783)
2 parents 325bc64 + 460ee37 commit 71bee19

File tree

2 files changed

+87
-74
lines changed

2 files changed

+87
-74
lines changed

articles/active-directory/develop/msal-authentication-flows.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,4 @@ Apart from the [Integrated Windows Authentication constraints](#integrated-windo
229229

230230
### Azure AD B2C specifics
231231

232-
For more information on using MSAL.NET and Azure AD B2C, see [Using ROPC with Azure AD B2C (MSAL.NET)](msal-net-aad-b2c-considerations.md#resource-owner-password-credentials-ropc-with-azure-ad-b2c).
232+
For more information on using ROPC in MSAL.NET and Azure AD B2C, see [Using ROPC with Azure AD B2C](msal-net-aad-b2c-considerations.md#resource-owner-password-credentials-ropc).
Lines changed: 86 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
title: Azure AD B2C (MSAL.NET) | Azure
2+
title: Azure AD B2C and MSAL.NET
33
titleSuffix: Microsoft identity platform
4-
description: Learn about specific considerations when using Azure AD B2C with the Microsoft Authentication Library for .NET (MSAL.NET).
4+
description: Considerations when using Azure AD B2C with the Microsoft Authentication Library for .NET (MSAL.NET).
55
services: active-directory
66
author: mmacy
77
manager: CelesteDG
@@ -10,35 +10,37 @@ ms.service: active-directory
1010
ms.subservice: develop
1111
ms.topic: conceptual
1212
ms.workload: identity
13-
ms.date: 10/29/2019
13+
ms.date: 05/07/2020
1414
ms.author: jeferrie
1515
ms.reviewer: saeeda
1616
ms.custom: aaddev
17-
#Customer intent: As an application developer, I want to learn about specific considerations when using Azure AD B2C and MSAL.NET so I can decide if this platform meets my application development needs and requirements.
17+
# Customer intent: As an application developer, I want to learn about specific considerations when using
18+
# Azure AD B2C and MSAL.NET so I can decide if this platform meets my application development
19+
# needs and requirements.
1820
---
1921

2022
# Use MSAL.NET to sign in users with social identities
2123

2224
You can use MSAL.NET to sign in users with social identities by using [Azure Active Directory B2C (Azure AD B2C)](https://aka.ms/aadb2c). Azure AD B2C is built around the notion of policies. In MSAL.NET, specifying a policy translates to providing an authority.
2325

24-
- When you instantiate the public client application, you need to specify the policy in authority.
25-
- When you want to apply a policy, you need to call an override of `AcquireTokenInteractive` containing an `authority` parameter.
26+
- When you instantiate the public client application, you need to specify the policy as part of the authority.
27+
- When you want to apply a policy, call an override of `AcquireTokenInteractive` that accepts the `authority` parameter.
2628

27-
This page is for MSAL 3.x. If you are interested in MSAL 2.x, please see [Azure AD B2C specifics in MSAL 2.x](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/AAD-B2C-Specifics-MSAL-2.x).
29+
This article applies to MSAL.NET 3.x. For MSAL.NET 2.x, see [Azure AD B2C specifics in MSAL 2.x](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/AAD-B2C-Specifics-MSAL-2.x) in the MSAL.NET Wiki on GitHub.
2830

29-
## Authority for a Azure AD B2C tenant and policy
31+
## Authority for an Azure AD B2C tenant and policy
3032

31-
The authority to use is `https://{azureADB2CHostname}/tfp/{tenant}/{policyName}` where:
33+
The authority format for Azure AD B2C is: `https://{azureADB2CHostname}/tfp/{tenant}/{policyName}`
3234

33-
- `azureADB2CHostname` is the name of the Azure AD B2C tenant plus the host (for example `{your-tenant-name}.b2clogin.com`),
34-
- `tenant` is the full name of the Azure AD B2C tenant (for example, `{your-tenant-name}.onmicrosoft.com`) or the GUID for the tenant,
35-
- `policyName` the name of the policy or user flow to apply (for instance "b2c_1_susi" for sign-up/sign-in).
35+
- `azureADB2CHostname` - The name of the Azure AD B2C tenant plus the host. For example, *contosob2c.b2clogin.com*.
36+
- `tenant` - The domain name or the directory (tenant) ID of the Azure AD B2C tenant. For example, *contosob2c.onmicrosoft.com* or a GUID, respectively.
37+
- `policyName` - The name of the user flow or custom policy to apply. For example, a sign-up/sign-in policy like *b2c_1_susi*.
3638

37-
For more information on the Azure AD B2C authorities, see this [documentation](/azure/active-directory-b2c/b2clogin).
39+
For more information about Azure AD B2C authorities, see [Set redirect URLs to b2clogin.com](../../active-directory-b2c/b2clogin.md).
3840

3941
## Instantiating the application
4042

41-
When building the application, you need to provide the authority.
43+
Provide the authority by calling `WithB2CAuthority()` when you create the application object:
4244

4345
```csharp
4446
// Azure AD B2C Coordinates
@@ -61,125 +63,136 @@ application = PublicClientApplicationBuilder.Create(ClientID)
6163

6264
## Acquire a token to apply a policy
6365

64-
Acquiring a token for an Azure AD B2C protected API in a public client application requires you to use the overrides with an authority:
66+
Acquiring a token for an Azure AD B2C-protected API in a public client application requires you to use the overrides with an authority:
6567

6668
```csharp
6769
IEnumerable<IAccount> accounts = await application.GetAccountsAsync();
68-
AuthenticationResult ar = await application .AcquireTokenInteractive(scopes)
69-
.WithAccount(GetAccountByPolicy(accounts, policy))
70-
.WithParentActivityOrWindow(ParentActivityOrWindow)
71-
.ExecuteAsync();
70+
AuthenticationResult ar = await application.AcquireTokenInteractive(scopes)
71+
.WithAccount(GetAccountByPolicy(accounts, policy))
72+
.WithParentActivityOrWindow(ParentActivityOrWindow)
73+
.ExecuteAsync();
7274
```
7375

74-
with:
76+
In the preceding code snippet:
7577

76-
- `policy` being one of the previous strings (for instance `PolicySignUpSignIn`).
77-
- `ParentActivityOrWindow` is required for Android (the Activity), and optional for other platforms which support the parent UI, such as windows in Windows and UIViewController in iOS. See more information [here on the UI dialog](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Acquiring-tokens-interactively#withparentactivityorwindow).
78+
- `policy` is a string containing the name of your Azure AD B2C user flow or custom policy (for example, `PolicySignUpSignIn`).
79+
- `ParentActivityOrWindow` is required for Android (the Activity) and is optional for other platforms that support a parent UI like windows on Microsoft Windows and UIViewController in iOS. For more information on the UI dialog, see [WithParentActivityOrWindow](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Acquiring-tokens-interactively#withparentactivityorwindow) on the MSAL Wiki.
7880
- `GetAccountByPolicy(IEnumerable<IAccount>, string)` is a method that finds an account for a given policy. For example:
7981

8082
```csharp
8183
private IAccount GetAccountByPolicy(IEnumerable<IAccount> accounts, string policy)
8284
{
83-
foreach (var account in accounts)
84-
{
85-
string userIdentifier = account.HomeAccountId.ObjectId.Split('.')[0];
86-
if (userIdentifier.EndsWith(policy.ToLower()))
87-
return account;
88-
}
89-
return null;
85+
foreach (var account in accounts)
86+
{
87+
string userIdentifier = account.HomeAccountId.ObjectId.Split('.')[0];
88+
if (userIdentifier.EndsWith(policy.ToLower()))
89+
return account;
90+
}
91+
return null;
9092
}
9193
```
9294

93-
Applying a policy or user flow (for example, letting the end user edit their profile or reset their password) is currently done by calling `AcquireTokenInteractive`. In the case of these two policies, you don't use the returned token / authentication result.
95+
Applying a user flow or custom policy (for example, letting the user edit their profile or reset their password) is currently done by calling `AcquireTokenInteractive`. For these two policies, you don't use the returned token/authentication result.
9496

95-
## Special case of EditProfile and ResetPassword policies
97+
## Profile edit policies
9698

97-
When you want to provide an experience where your end users sign in with a social identity and then edit their profile, you want to apply the Azure AD B2C Edit Profile policy. The way to do this is by calling `AcquireTokenInteractive` with
98-
the specific authority for that policy, and a Prompt set to `Prompt.NoPrompt` to prevent the account selection dialog from being displayed (as the user is already signed-in and has an active cookie session).
99+
To enable your users to sign in with a social identity and then edit their profile, apply the Azure AD B2C edit profile policy.
100+
101+
Do so by calling `AcquireTokenInteractive` with the authority for that policy. Because the user is already signed in and has an active cookie session, use `Prompt.NoPrompt` to prevent the account selection dialog from being displayed.
99102

100103
```csharp
101104
private async void EditProfileButton_Click(object sender, RoutedEventArgs e)
102105
{
103-
IEnumerable<IAccount> accounts = await app.GetAccountsAsync();
104-
try
105-
{
106-
var authResult = await app.AcquireToken(scopes:App.ApiScopes)
107-
.WithAccount(GetUserByPolicy(accounts, App.PolicyEditProfile)),
108-
.WithPrompt(Prompt.NoPrompt),
109-
.WithB2CAuthority(App.AuthorityEditProfile)
110-
.ExecuteAsync();
111-
DisplayBasicTokenInfo(authResult);
112-
}
113-
catch
114-
{
115-
. . .
116-
}
106+
IEnumerable<IAccount> accounts = await app.GetAccountsAsync();
107+
try
108+
{
109+
var authResult = await app.AcquireToken(scopes:App.ApiScopes)
110+
.WithAccount(GetUserByPolicy(accounts, App.PolicyEditProfile)),
111+
.WithPrompt(Prompt.NoPrompt),
112+
.WithB2CAuthority(App.AuthorityEditProfile)
113+
.ExecuteAsync();
114+
DisplayBasicTokenInfo(authResult);
115+
}
116+
catch
117+
{
118+
}
117119
}
118120
```
119-
## Resource owner password credentials (ROPC) with Azure AD B2C
120-
For more details on the ROPC flow, please see this [documentation](v2-oauth-ropc.md).
121121

122-
This flow is **not recommended** because your application asking a user for their password is not secure. For more information about this problem, see [this article](https://news.microsoft.com/features/whats-solution-growing-problem-passwords-says-microsoft/).
122+
## Resource owner password credentials (ROPC)
123+
124+
For more information on the ROPC flow, see [Sign in with resource owner password credentials grant](v2-oauth-ropc.md).
125+
126+
The ROPC flow is **not recommended** because asking a user for their password in your application is not secure. For more information about this problem, see [What’s the solution to the growing problem of passwords?](https://news.microsoft.com/features/whats-solution-growing-problem-passwords-says-microsoft/).
127+
128+
By using username/password in an ROPC flow, you sacrifice several things:
123129

124-
By using username/password, you are giving up a number of things:
125-
- Core tenets of modern identity: password gets fished, replayed. Because we have this concept of a share secret that can be intercepted. This is incompatible with passwordless.
130+
- Core tenets of modern identity: The password can be fished or replayed because the shared secret can be intercepted. By definition, ROPC is incompatible with passwordless flows.
126131
- Users who need to do MFA won't be able to sign in (as there is no interaction).
127-
- Users won't be able to do single sign-on.
132+
- Users won't be able to use single sign-on (SSO).
128133

129134
### Configure the ROPC flow in Azure AD B2C
130-
In your Azure AD B2C tenant, create a new user flow and select **Sign in using ROPC**. This will enable the ROPC policy for your tenant. See [Configure the resource owner password credentials flow](/azure/active-directory-b2c/configure-ropc) for more details.
131135

132-
`IPublicClientApplication` contains a method:
136+
In your Azure AD B2C tenant, create a new user flow and select **Sign in using ROPC** to enable ROPC for the user flow. For more information, see [Configure the resource owner password credentials flow](/azure/active-directory-b2c/configure-ropc).
137+
138+
`IPublicClientApplication` contains the `AcquireTokenByUsernamePassword` method:
139+
133140
```csharp
134141
AcquireTokenByUsernamePassword(
135142
IEnumerable<string> scopes,
136143
string username,
137144
SecureString password)
138145
```
139146

140-
This method takes as parameters:
141-
- The *scopes* to request an access token for.
147+
This `AcquireTokenByUsernamePassword` method takes the following parameters:
148+
149+
- The *scopes* for which to obtain an access token.
142150
- A *username*.
143151
- A SecureString *password* for the user.
144152

145-
Remember to use the authority that contains the ROPC policy.
146-
147153
### Limitations of the ROPC flow
148-
- The ROPC flow **only works for local accounts** (where you register with Azure AD B2C using an email or username). This flow does not work if federating to any of the identity providers supported by Azure AD B2C (Facebook, Google, etc.).
149154

150-
## Google Auth and Embedded Webview
155+
The ROPC flow **only works for local accounts**, where your users have registered with Azure AD B2C using an email address or username. This flow doesn't work when federating to an external identity provider supported by Azure AD B2C (Facebook, Google, etc.).
156+
157+
## Google auth and embedded webview
151158

152-
If you are a Azure AD B2C developer using Google as an identity provider we recommand you use the system browser, as Google does not allow [authentication from embedded webviews](https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html). Currently, `login.microsoftonline.com` is a trusted authority with Google. Using this authority will work with embedded webview. However using `b2clogin.com` is not a trusted authority with Google, so users will not be able to authenticate.
159+
If you're using Google as an identity provider, we recommend you use the system browser as Google doesn't allow [authentication from embedded webviews](https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html). Currently, `login.microsoftonline.com` is a trusted authority with Google and will work with embedded webview. However, `b2clogin.com` is not a trusted authority with Google, so users will not be able to authenticate.
153160

154-
We will provide an update to this [issue](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/688) if things change.
161+
We'll provide an update to this [issue](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/688) if things change.
155162

156-
## Caching with Azure AD B2C in MSAL.Net
163+
## Token caching in MSAL.NET
157164

158165
### Known issue with Azure AD B2C
159166

160-
MSAL.Net supports a [token cache](/dotnet/api/microsoft.identity.client.tokencache?view=azure-dotnet). The token caching key is based on the claims returned by the Identity Provider. Currently MSAL.Net needs two claims to build a token cache key:
161-
- `tid` which is the Azure AD Tenant ID, and
167+
MSAL.NET supports a [token cache](/dotnet/api/microsoft.identity.client.tokencache?view=azure-dotnet). The token caching key is based on the claims returned by the identity provider (IdP).
168+
169+
Currently, MSAL.NET needs two claims to build a token cache key:
170+
171+
- `tid` (the Azure AD tenant ID)
162172
- `preferred_username`
163173

164-
Both these claims are missing in many of the Azure AD B2C scenarios.
174+
Both of these claims may be missing in Azure AD B2C scenarios because not all social identity providers (Facebook, Google, and others) return them in the tokens they return to Azure AD B2C.
165175

166-
The customer impact is that when trying to display the username field, are you getting "Missing from the token response" as the value? If so, this is because Azure AD B2C does not return a value in the IdToken for the preferred_username because of limitations with the social accounts and external identity providers (IdPs). Azure AD returns a value for preferred_username because it knows who the user is, but for Azure AD B2C, because the user can sign in with a local account, Facebook, Google, GitHub, etc. there is not a consistent value for Azure AD B2C to use for preferred_username. To unblock MSAL from rolling out cache compatibility with ADAL, we decided to use "Missing from the token response" on our end when dealing with the Azure AD B2C accounts when the IdToken returns nothing for preferred_username. MSAL must return a value for preferred_username to maintain cache compatibility across libraries.
176+
A symptom of such a scenario is that MSAL.NET returns `Missing from the token response` when you access the `preferred_username` claim value in tokens issued by Azure AD B2C. MSAL uses the `Missing from the token response` value for `preferred_username` to maintain cache cross-compatibility between libraries.
167177

168178
### Workarounds
169179

170-
#### Mitigation for the missing tenant ID
180+
#### Mitigation for missing tenant ID
171181

172-
The suggested workaround is to use the [Caching by Policy](#acquire-a-token-to-apply-a-policy)
182+
The suggested workaround is to use [caching by policy](#acquire-a-token-to-apply-a-policy) described earlier.
173183

174-
Alternatively, you can use the `tid` claim, if you are using the [B2C custom policies](https://aka.ms/ief), because it provides the capability to return additional claims to the application. To learn more about [Claims Transformation](/azure/active-directory-b2c/claims-transformation-technical-profile)
184+
Alternatively, you can use the `tid` claim if you're using [custom policies](../../active-directory-b2c/custom-policy-get-started.md) in Azure AD B2C. Custom policies can return additional claims to your application by using [claims transformation](/azure/active-directory-b2c/claims-transformation-technical-profile).
175185

176186
#### Mitigation for "Missing from the token response"
177-
One option is to use the "name" claim as the preferred username. The process is mentioned in this [B2C doc](../../active-directory-b2c/user-flow-overview.md) -> "In the Return claim column, choose the claims you want returned in the authorization tokens sent back to your application after a successful profile editing experience. For example, select Display Name, Postal Code.”
187+
188+
One option is to use the `name` claim instead of `preferred_username`. To include the `name` claim in ID tokens issued by Azure AD B2C, select **Display Name** when you configure your user flow.
189+
190+
For more information about specifying which claims are returned by your user flows, see [Tutorial: Create user flows in Azure AD B2C](../../active-directory-b2c/tutorial-create-user-flows.md).
178191

179192
## Next steps
180193

181194
More details about acquiring tokens interactively with MSAL.NET for Azure AD B2C applications are provided in the following sample.
182195

183196
| Sample | Platform | Description|
184197
|------ | -------- | -----------|
185-
|[active-directory-b2c-xamarin-native](https://github.com/Azure-Samples/active-directory-b2c-xamarin-native) | Xamarin iOS, Xamarin Android, UWP | A simple Xamarin Forms app showcasing how to use MSAL.NET to authenticate users via Azure AD B2C, and access a web API with the resulting tokens.|
198+
|[active-directory-b2c-xamarin-native](https://github.com/Azure-Samples/active-directory-b2c-xamarin-native) | Xamarin iOS, Xamarin Android, UWP | A Xamarin Forms app that uses MSAL.NET to authenticate users via Azure AD B2C and then access a web API with the tokens returned.|

0 commit comments

Comments
 (0)