diff --git a/Microsoft.Identity.Web/AccountExtensions.cs b/Microsoft.Identity.Web/AccountExtensions.cs
index 5f739a6a..9a33dd96 100644
--- a/Microsoft.Identity.Web/AccountExtensions.cs
+++ b/Microsoft.Identity.Web/AccountExtensions.cs
@@ -24,8 +24,8 @@ public static ClaimsPrincipal ToClaimsPrincipal(this IAccount account)
return new ClaimsPrincipal(
new ClaimsIdentity(new Claim[]
{
- new Claim(ClaimConstants.Oid, account.HomeAccountId.ObjectId),
- new Claim(ClaimConstants.Tid, account.HomeAccountId.TenantId),
+ new Claim(ClaimConstants.Oid, account.HomeAccountId?.ObjectId),
+ new Claim(ClaimConstants.Tid, account.HomeAccountId?.TenantId),
new Claim(ClaimTypes.Upn, account.Username)
})
);
diff --git a/Microsoft.Identity.Web/AuthorizeForScopesAttribute.cs b/Microsoft.Identity.Web/AuthorizeForScopesAttribute.cs
index bf166972..46db3167 100644
--- a/Microsoft.Identity.Web/AuthorizeForScopesAttribute.cs
+++ b/Microsoft.Identity.Web/AuthorizeForScopesAttribute.cs
@@ -15,10 +15,8 @@
namespace Microsoft.Identity.Web
{
- // TODO: rename to EnsureScopesAttribute ? or MsalAuthorizeForScopesAttribute or AuthorizeForScopesAttribute
-
///
- /// Filter used on a controller action to trigger an incremental consent.
+ /// Filter used on a controller action to trigger incremental consent.
///
///
/// The following controller action will trigger
@@ -42,7 +40,7 @@ public class AuthorizeForScopesAttribute : ExceptionFilterAttribute
public string ScopeKeySection { get; set; }
///
- /// Handles the MsaUiRequiredExeception
+ /// Handles the MsalUiRequiredException
///
/// Context provided by ASP.NET Core
public override void OnException(ExceptionContext context)
@@ -55,7 +53,7 @@ public override void OnException(ExceptionContext context)
if (msalUiRequiredException != null)
{
- if (CanBeSolvedByReSignInUser(msalUiRequiredException))
+ if (CanBeSolvedByReSignInOfUser(msalUiRequiredException))
{
// the users cannot provide both scopes and ScopeKeySection at the same time
if (!string.IsNullOrWhiteSpace(ScopeKeySection) && Scopes != null && Scopes.Length > 0)
@@ -85,7 +83,7 @@ public override void OnException(ExceptionContext context)
base.OnException(context);
}
- private bool CanBeSolvedByReSignInUser(MsalUiRequiredException ex)
+ private bool CanBeSolvedByReSignInOfUser(MsalUiRequiredException ex)
{
// ex.ErrorCode != MsalUiRequiredException.UserNullError indicates a cache problem.
// When calling an [Authenticate]-decorated controller we expect an authenticated
@@ -97,22 +95,26 @@ private bool CanBeSolvedByReSignInUser(MsalUiRequiredException ex)
}
///
- /// Build Authentication properties needed for an incremental consent.
+ /// Build Authentication properties needed for incremental consent.
///
/// Scopes to request
/// MsalUiRequiredException instance
/// current http context in the pipeline
/// AuthenticationProperties
private AuthenticationProperties BuildAuthenticationPropertiesForIncrementalConsent(
- string[] scopes, MsalUiRequiredException ex, HttpContext context)
+ string[] scopes,
+ MsalUiRequiredException ex,
+ HttpContext context)
{
var properties = new AuthenticationProperties();
- // Set the scopes, including the scopes that ADAL.NET / MASL.NET need for the Token cache
- string[] additionalBuildInScopes =
- {OidcConstants.ScopeOpenId, OidcConstants.ScopeOfflineAccess, OidcConstants.ScopeProfile};
+ // Set the scopes, including the scopes that ADAL.NET / MSAL.NET need for the token cache
+ string[] additionalBuiltInScopes =
+ {OidcConstants.ScopeOpenId,
+ OidcConstants.ScopeOfflineAccess,
+ OidcConstants.ScopeProfile};
properties.SetParameter>(OpenIdConnectParameterNames.Scope,
- scopes.Union(additionalBuildInScopes).ToList());
+ scopes.Union(additionalBuiltInScopes).ToList());
// Attempts to set the login_hint to avoid the logged-in user to be presented with an account selection dialog
var loginHint = context.User.GetLoginHint();
diff --git a/Microsoft.Identity.Web/ClaimsPrincipalExtensions.cs b/Microsoft.Identity.Web/ClaimsPrincipalExtensions.cs
index ecc3bf9b..06257a21 100644
--- a/Microsoft.Identity.Web/ClaimsPrincipalExtensions.cs
+++ b/Microsoft.Identity.Web/ClaimsPrincipalExtensions.cs
@@ -34,7 +34,7 @@ public static string GetMsalAccountId(this ClaimsPrincipal claimsPrincipal)
///
/// Gets the unique object ID associated with the
///
- /// the from which to retrieve the unique object id
+ /// the from which to retrieve the unique object ID
/// This method returns the object ID both in case the developer has enabled or not claims mapping
/// Unique object ID of the identity, or null if it cannot be found
public static string GetObjectId(this ClaimsPrincipal claimsPrincipal)
@@ -50,9 +50,9 @@ public static string GetObjectId(this ClaimsPrincipal claimsPrincipal)
///
/// Gets the Tenant ID associated with the
///
- /// the from which to retrieve the tenant id
+ /// the from which to retrieve the tenant ID
/// Tenant ID of the identity, or null if it cannot be found
- /// This method returns the object ID both in case the developer has enabled or not claims mapping
+ /// This method returns the tenant ID both in case the developer has enabled or not claims mapping
public static string GetTenantId(this ClaimsPrincipal claimsPrincipal)
{
string tenantId = claimsPrincipal.FindFirstValue(ClaimConstants.Tid);
@@ -95,27 +95,29 @@ public static string GetDomainHint(this ClaimsPrincipal claimsPrincipal)
/// Get the display name for the signed-in user, from the
///
/// Claims about the user/account
- /// A string containing the display name for the user, as brought by Azure AD (v1.0) and Microsoft identity platform (v2.0) tokens,
+ /// A string containing the display name for the user, as determined by Azure AD (v1.0) and Microsoft identity platform (v2.0) tokens,
/// or null if the claims cannot be found
/// See https://docs.microsoft.com/azure/active-directory/develop/id-tokens#payload-claims
public static string GetDisplayName(this ClaimsPrincipal claimsPrincipal)
{
- // Use the claims in an Microsoft identity platform token first
+ // Use the claims in a Microsoft identity platform token first
string displayName = claimsPrincipal.FindFirstValue(ClaimConstants.PreferredUserName);
- // Otherwise fall back to the claims in an Azure AD v1.0 token
- if (string.IsNullOrWhiteSpace(displayName))
+ if (!string.IsNullOrWhiteSpace(displayName))
{
- displayName = claimsPrincipal.FindFirstValue(ClaimsIdentity.DefaultNameClaimType);
+ return displayName;
}
- // Finally falling back to name
- if (string.IsNullOrWhiteSpace(displayName))
+ // Otherwise fall back to the claims in an Azure AD v1.0 token
+ displayName = claimsPrincipal.FindFirstValue(ClaimsIdentity.DefaultNameClaimType);
+
+ if (!string.IsNullOrWhiteSpace(displayName))
{
- displayName = claimsPrincipal.FindFirstValue(ClaimConstants.Name);
+ return displayName;
}
- return displayName;
- }
+ // Finally falling back to name
+ return claimsPrincipal.FindFirstValue(ClaimConstants.Name);
+ }
}
}
diff --git a/Microsoft.Identity.Web/Extensions.cs b/Microsoft.Identity.Web/Extensions.cs
index 56a16e7c..4e710eb4 100644
--- a/Microsoft.Identity.Web/Extensions.cs
+++ b/Microsoft.Identity.Web/Extensions.cs
@@ -1,11 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
namespace Microsoft.Identity.Web
{
///
- /// Extension methods that don't fit in any other class
+ /// Extension methods
///
public static class Extensions
{
diff --git a/Microsoft.Identity.Web/HttpContextExtensions.cs b/Microsoft.Identity.Web/HttpContextExtensions.cs
index 36ae973b..f69eb944 100644
--- a/Microsoft.Identity.Web/HttpContextExtensions.cs
+++ b/Microsoft.Identity.Web/HttpContextExtensions.cs
@@ -1,4 +1,7 @@
-using Microsoft.AspNetCore.Http;
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.AspNetCore.Http;
using System.IdentityModel.Tokens.Jwt;
namespace Microsoft.Identity.Web
diff --git a/Microsoft.Identity.Web/ITokenAcquisition.cs b/Microsoft.Identity.Web/ITokenAcquisition.cs
index d4410d35..f57171c7 100644
--- a/Microsoft.Identity.Web/ITokenAcquisition.cs
+++ b/Microsoft.Identity.Web/ITokenAcquisition.cs
@@ -46,13 +46,13 @@ public interface ITokenAcquisition
///
/// Typically used from an ASP.NET Core Web App or Web API controller, this method gets an access token
- /// for a downstream API on behalf of the user account which claims are provided in the
+ /// for a downstream API on behalf of the user account in which claims are provided in the
/// member of the parameter
///
/// HttpContext associated with the Controller or auth operation
/// Scopes to request for the downstream API to call
/// Enables to override the tenant/account for the same identity. This is useful in the
- /// cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant
+ /// cases where a given account is a guest in other tenants, and you want to acquire tokens for a specific tenant
/// An access token to call on behalf of the user, the downstream API characterized by its scopes
Task GetAccessTokenOnBehalfOfUserAsync(IEnumerable scopes, string tenantId = null);
@@ -66,8 +66,8 @@ public interface ITokenAcquisition
///
/// Used in Web APIs (which therefore cannot have an interaction with the user).
- /// Replies to the client through the HttpReponse by sending a 403 (forbidden) and populating wwwAuthenticateHeaders so that
- /// the client can trigger an interaction with the user so that the user consents to more scopes
+ /// Replies to the client through the HttpResponse by sending a 403 (forbidden) and populating wwwAuthenticateHeaders so that
+ /// the client can trigger an interaction with the user so the user can consent to more scopes
///
/// Scopes to consent to
/// triggering the challenge
diff --git a/Microsoft.Identity.Web/README.md b/Microsoft.Identity.Web/README.md
index 9a07e42d..d5843a2c 100644
--- a/Microsoft.Identity.Web/README.md
+++ b/Microsoft.Identity.Web/README.md
@@ -62,16 +62,16 @@ public class Startup
}
```
-This method adds authentication with the Microsoft Identity platform (formerly Azure AD v2.0). This includes validating the token in all scenarios (single tenant application, multi tenant applications) in Azure public cloud as well as national clouds.
+This method adds authentication with the Microsoft identity platform. This includes validating the token in all scenarios (single tenant application, multi tenant applications) in Azure public cloud, as well as national clouds.
See also:
-- the [ASP.NET Core Web app incremental tutorial](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/1-WebApp-OIDC/1-1-MyOrg) in chapter 1.1 (sign-in user in an organization)
+- The [ASP.NET Core Web app incremental tutorial](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/1-WebApp-OIDC/1-1-MyOrg) in chapter 1.1 (sign-in user in an organization)
- The [Web App that signs-in users](https://docs.microsoft.com/azure/active-directory/develop/scenario-web-app-sign-user-overview) scenario landing page in the Microsoft identity platform documentation and the following pages.
### Web apps that sign in users and call web apis on behalf of the signed-in user - startup.cs
-If moreover you want your Web app to call web APIS, you'll need to add a line with `.AddWebAppCallsProtectedWebApi()`, and choose a token cache implementation, for instance `.AddInMemoryTokenCaches()`
+If you want your web app to call web APIs, you'll need to add a line with `.AddWebAppCallsProtectedWebApi()`, and choose a token cache implementation, for instance `.AddInMemoryTokenCaches()`
```CSharp
using Microsoft.Identity.Web;
@@ -95,7 +95,7 @@ public class Startup
Note that by default, `AddSignIn` gets the configuration from the "AzureAD" section of the configuration files. It has
several parameters that you can change.
-Also the proposed token cache serialization is in memory. you can also use the session cache, or various distributed caches
+Also the proposed token cache serialization is in memory. You can also use the session cache, or various distributed caches.
### Web app controller
@@ -136,16 +136,16 @@ public class HomeController : Controller
}
```
-The controller action is decorated by an attribute `AuthorizeForScopesAttribute` which enables to process the `MsalUiRequiredException` that could be thrown by the service implementing `ITokenAcquisition.GetAccessTokenOnBehalfOfUserAsync` so that the web app interacts with the user, and ask them to consent to the scopes, or re-sign-in if needed.
+The controller action is decorated by an attribute `AuthorizeForScopesAttribute` which enables it to process the `MsalUiRequiredException` that could be thrown by the service implementing `ITokenAcquisition.GetAccessTokenOnBehalfOfUserAsync` so that the web app interacts with the user, and asks them to consent to the scopes, or re-sign-in if needed.
### Samples and documentation
-You can see in details how the library is used in the following samples:
+You can learn about how the library is used in the following samples:
-- [ASP.NET Core Web app incremental tutorial](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2) in chapter 2.1 ([call Microsoft Graph on behalf of signed in user](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-1-Call-MSGraph))
-- [ASP.NET Core Web app incremental tutorial](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2) in chapter 2.2 ([call Microsoft Graph on behalf of signed in user with a SQL token cache](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-2-TokenCache))
+- [ASP.NET Core Web app incremental tutorial](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2) in chapter 2.1 ([call Microsoft Graph on behalf of a signed in user](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-1-Call-MSGraph))
+- [ASP.NET Core Web app incremental tutorial](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2) in chapter 2.2 ([call Microsoft Graph on behalf of a signed in user with a SQL token cache](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-2-TokenCache))
- The [Web app that calls web apis](https://docs.microsoft.com/azure/active-directory/develop/scenario-web-app-sign-user-overview) scenario landing page in the Microsoft identity platform documentation
## Web APIs
@@ -154,9 +154,9 @@ The library also enables web APIs to work with the Microsoft identity platform,

-### Protected web APIS - Startup.cs
+### Protected web APIs - Startup.cs
-To enable the web API to accept tokens emitted by the Microsoft identity platform, you need to replace, in your web API Startup.cs file, the call to:
+To enable the web API to accept tokens emitted by the Microsoft identity platform, you need to replace, in your web API Startup.cs file, the call to:
```CSharp
using Microsoft.Identity.Web;
@@ -193,16 +193,16 @@ public class Startup
}
```
-This method enables your web API to be protected using the Microsoft Identity platform (formerly Azure AD v2.0). It takes care of validating the token in all scenarios (single tenant application, multi tenant applications), in Azure public cloud as well as national clouds.
+This method enables your web API to be protected using the Microsoft identity platform. It takes care of validating the token in all scenarios (single tenant application, multi tenant applications), in Azure public cloud, as well as national clouds.
See also:
- the [ASP.NET Core Web API incremental tutorial](https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2) in chapter 1.1 ([Protect the web api](https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/tree/master/1.%20Desktop%20app%20calls%20Web%20API))
-- The [Protected web API](https://docs.microsoft.com/azure/active-directory/develop/scenario-protected-web-api-overview) scenario landing page in the Microsoft identity platform documentation and the following pages.
+- the [Protected web API](https://docs.microsoft.com/azure/active-directory/develop/scenario-protected-web-api-overview) scenario landing page in the Microsoft identity platform documentation and the following pages.
### Protected web APIs that call downstream APIs on behalf of a user - Startup.cs
-If moreover you want your web API to call downstream web APIS, you'll need to add lines with `.AddProtectedWebApiCallsProtectedWebApi()`, and choose a token cache implementation, for instance `.AddInMemoryTokenCaches()`
+If you want your web API to call downstream web APIS, you'll need to add lines with `.AddProtectedWebApiCallsProtectedWebApi()`, and choose a token cache implementation, for instance `.AddInMemoryTokenCaches()`
```CSharp
using Microsoft.Identity.Web;
@@ -266,11 +266,11 @@ public class HomeController : Controller
#### Handle conditional access
-It can happen that when your web api tries to get a token for the downstream API, the token acquisition service throws a `MsalUiRequiredException` meaning that the user on the client calling the web API needs to perform more actions such as multi-factor authentication. Given that the web API isn't capable of doing interaction itself, this exception needs to be passed to the client. To propagate back this exception to the client, you can catch the exception and call the `ITokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeader` method.
+It can happen that when your web API tries to get a token for the downstream API, the token acquisition service throws a `MsalUiRequiredException` meaning that the user on the client calling the web API needs to perform more actions such as multi-factor authentication. Given that the web API isn't capable of doing interaction itself, this exception needs to be passed to the client. To propagate this exception back to the client, you catch the exception and call the `ITokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeader` method.
## Token cache serialization
-For web apps that calls web apis, and web APIs that call downstream APIs, the code snippets above show the use of the In Memory token cache serialization. The library proposes alternate token cache serialization methods:
+For web apps that calls web APIs, and web APIs that call downstream APIs, the code snippets above show the use of the In Memory token cache serialization. The library proposes alternate token cache serialization methods:
| Extension Method | Microsoft.Identity.Web sub Namespace | Description |
| ---------------- | --------- | ------------ |
@@ -329,7 +329,7 @@ In the other direction `ClaimsPrincipalFactory` instantiates a `ClaimsPrincipal`
### AccountExtensions
-Finally, you can create a `ClaimsPrincipal` from an instance of MSAL.NET `IAccount`, using the `ToClaimsPrincipal` method in `AccountExtensions`.
+Finally, you can create a `ClaimsPrincipal` from an instance of MSAL.NET `IAccount`, using the `ToClaimsPrincipal` method in `AccountExtensions`.
@@ -349,7 +349,7 @@ In both cases, you can set a breakpoint in the methods of the `OpenIdConnectMid
If you want to customize the `OpenIdConnectOption` or `JwtBearerOption` but still want to benefit from the implementation provided by Microsoft.Identity.Web, you can easily do it from your `Startup.cs` file:
-Lets take for example the method `AddProtectedWebApi`. If you check the code inside it, you have this event setup:
+Let's take for example the method `AddProtectedWebApi`. If you check the code inside it, you have this event setup:
```
options.Events.OnTokenValidated = async context =>
@@ -366,7 +366,7 @@ options.Events.OnTokenValidated = async context =>
};
```
-Lets say you want to augment the current `ClaimsPrincipal` by adding claims to it, and you have to do it on `OnTokenValidated `, however you don't want to lose this `UnauthorizedAccessException` check existing in the event. To do so, on your `Startup.cs` you would have:
+Let's say you want to augment the current `ClaimsPrincipal` by adding claims to it, and you have to do it on `OnTokenValidated `, however you don't want to lose this `UnauthorizedAccessException` check existing in the event. To do so, on your `Startup.cs` you would have:
```
services.AddProtectedWebApi(Configuration);
diff --git a/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs b/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs
index 1ba7ca07..2370becf 100644
--- a/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs
+++ b/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs
@@ -15,7 +15,7 @@ public static class ScopesRequiredHttpContextExtensions
///
/// When applied to an , verifies that the user authenticated in the
/// web API has any of the accepted scopes.
- /// If the authentication user does not have any of these , the
+ /// If the authenticated user does not have any of these , the
/// method throws an HTTP Unauthorized with the message telling which scopes are expected in the token
///
/// Scopes accepted by this web API
@@ -27,7 +27,9 @@ public static void VerifyUserHasAnyAcceptedScope(this HttpContext context, param
{
throw new ArgumentNullException(nameof(acceptedScopes));
}
+
Claim scopeClaim = context?.User?.FindFirst("http://schemas.microsoft.com/identity/claims/scope");
+
if (scopeClaim == null || !scopeClaim.Value.Split(' ').Intersect(acceptedScopes).Any())
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
diff --git a/Microsoft.Identity.Web/TokenAcquisition.cs b/Microsoft.Identity.Web/TokenAcquisition.cs
index 9455cb0e..619f7143 100644
--- a/Microsoft.Identity.Web/TokenAcquisition.cs
+++ b/Microsoft.Identity.Web/TokenAcquisition.cs
@@ -56,9 +56,9 @@ public TokenAcquisition(
}
///
- /// Scopes which are already requested by MSAL.NET. they should not be re-requested;
+ /// Scopes which are already requested by MSAL.NET. They should not be re-requested;
///
- private readonly string[] _scopesRequestedByMsalNet = new string[]
+ private readonly string[] _scopesRequestedByMsal = new string[]
{
OidcConstants.ScopeOpenId,
OidcConstants.ScopeProfile,
@@ -115,7 +115,7 @@ public async Task AddAccountToCacheFromAuthorizationCodeAsync(AuthorizationCodeR
context.HandleCodeRedemption();
// The cache will need the claims from the ID token.
- // If they are not yet in the HttpContext.User's claims, so adding them here.
+ // If they are not yet in the HttpContext.User's claims, add them here.
if (!context.HttpContext.User.Claims.Any())
{
(context.HttpContext.User.Identity as ClaimsIdentity).AddClaims(context.Principal.Claims);
@@ -127,7 +127,7 @@ public async Task AddAccountToCacheFromAuthorizationCodeAsync(AuthorizationCodeR
// case a further call to AcquireTokenByAuthorizationCodeAsync in the future is required for incremental consent (getting a code requesting more scopes)
// Share the ID Token though
var result = await application
- .AcquireTokenByAuthorizationCode(scopes.Except(_scopesRequestedByMsalNet), context.ProtocolMessage.Code)
+ .AcquireTokenByAuthorizationCode(scopes.Except(_scopesRequestedByMsal), context.ProtocolMessage.Code)
.ExecuteAsync()
.ConfigureAwait(false);
@@ -144,14 +144,14 @@ public async Task AddAccountToCacheFromAuthorizationCodeAsync(AuthorizationCodeR
///
/// Typically used from a Web App or WebAPI controller, this method retrieves an access token
/// for a downstream API using;
- /// 1) the token cache (for Web Apps and Web APis) if a token exists in the cache
+ /// 1) the token cache (for Web Apps and Web APIs) if a token exists in the cache
/// 2) or the on-behalf-of flow
/// in Web APIs, for the user account that is ascertained from claims are provided in the
/// instance of the current HttpContext
///
/// Scopes to request for the downstream API to call
/// Enables overriding of the tenant/account for the same identity. This is useful in the
- /// cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in
+ /// cases where a given account is a guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in
/// An access token to call the downstream API and populated with this downstream Api's scopes
/// Calling this method from a Web API supposes that you have previously called,
/// in a method called by JwtBearerOptions.Events.OnTokenValidated, the HttpContextExtensions.StoreTokenUsedToCallWebAPI method
@@ -176,8 +176,10 @@ public async Task GetAccessTokenOnBehalfOfUserAsync(
accessToken = await GetAccessTokenOnBehalfOfUserFromCacheAsync(application, CurrentHttpContext.User, scopes, tenant)
.ConfigureAwait(false);
}
- catch(MsalUiRequiredException ex)
+
+ catch (MsalUiRequiredException ex)
{
+ Debug.WriteLine(ex.Message);
// GetAccessTokenOnBehalfOfUserAsync is an abstraction that can be called from a Web App or a Web API
// to get a token for a Web API on behalf of the user, but not necessarily with the on behalf of OAuth2.0
// flow as this one only applies to Web APIs.
@@ -190,7 +192,7 @@ public async Task GetAccessTokenOnBehalfOfUserAsync(
string tokenUsedToCallTheWebApi = validatedToken.InnerToken == null ? validatedToken.RawData
: validatedToken.InnerToken.RawData;
var result = await application
- .AcquireTokenOnBehalfOf(scopes.Except(_scopesRequestedByMsalNet),
+ .AcquireTokenOnBehalfOf(scopes.Except(_scopesRequestedByMsal),
new UserAssertion(tokenUsedToCallTheWebApi))
.ExecuteAsync()
.ConfigureAwait(false);
@@ -340,7 +342,7 @@ private async Task GetAccessTokenOnBehalfOfUserFromCacheAsync(
if (string.IsNullOrWhiteSpace(tenant))
{
result = await application
- .AcquireTokenSilent(scopes.Except(_scopesRequestedByMsalNet), account)
+ .AcquireTokenSilent(scopes.Except(_scopesRequestedByMsal), account)
.ExecuteAsync()
.ConfigureAwait(false);
}
@@ -348,7 +350,7 @@ private async Task GetAccessTokenOnBehalfOfUserFromCacheAsync(
{
string authority = application.Authority.Replace(new Uri(application.Authority).PathAndQuery, $"/{tenant}/");
result = await application
- .AcquireTokenSilent(scopes.Except(_scopesRequestedByMsalNet), account)
+ .AcquireTokenSilent(scopes.Except(_scopesRequestedByMsal), account)
.WithAuthority(authority)
.ExecuteAsync()
.ConfigureAwait(false);
@@ -359,14 +361,14 @@ private async Task GetAccessTokenOnBehalfOfUserFromCacheAsync(
///
/// Used in Web APIs (which therefore cannot have an interaction with the user).
- /// Replies to the client through the HttpReponse by sending a 403 (forbidden) and populating wwwAuthenticateHeaders so that
- /// the client can trigger an iteraction with the user so that the user consents to more scopes
+ /// Replies to the client through the HttpResponse by sending a 403 (forbidden) and populating wwwAuthenticateHeaders so that
+ /// the client can trigger an interaction with the user so that the user consents to more scopes
///
/// Scopes to consent to
/// triggering the challenge
public void ReplyForbiddenWithWwwAuthenticateHeader(IEnumerable scopes, MsalUiRequiredException msalServiceException)
{
- // A user interaction is required, but we are in a Web API, and therefore, we need to report back to the client through an wwww-Authenticate header https://tools.ietf.org/html/rfc6750#section-3.1
+ // A user interaction is required, but we are in a Web API, and therefore, we need to report back to the client through a www-Authenticate header https://tools.ietf.org/html/rfc6750#section-3.1
string proposedAction = "consent";
if (msalServiceException.ErrorCode == MsalError.InvalidGrantError)
{
diff --git a/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs b/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs
index a935c655..d6526437 100644
--- a/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs
+++ b/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs
@@ -5,13 +5,12 @@
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
-using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
namespace Microsoft.Identity.Web.TokenCacheProviders.Distributed
{
///
- /// An implementation of token cache for both Confidential and Public clients backed by MemoryCache.
+ /// An implementation of the token cache for both Confidential and Public clients backed by MemoryCache.
///
///
public class MsalDistributedTokenCacheAdapter : MsalAbstractTokenCacheProvider
diff --git a/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheOptions.cs b/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheOptions.cs
index 11cb1f52..d430c484 100644
--- a/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheOptions.cs
+++ b/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheOptions.cs
@@ -6,14 +6,14 @@
namespace Microsoft.Identity.Web.TokenCacheProviders.InMemory
{
///
- /// MSAL's memory token cache options
+ /// MSAL's in-memory token cache options
///
public class MsalMemoryTokenCacheOptions
{
///
/// Gets or sets the value of the duration after which the cache entry will expire unless it's used
- /// This is the duration till the tokens are kept in memory cache.
- /// In production, a higher value , up-to 90 days is recommended.
+ /// This is the duration the tokens are kept in memory cache.
+ /// In production, a higher value, up-to 90 days is recommended.
///
///
/// The SlidingExpiration value.
@@ -28,7 +28,7 @@ public TimeSpan SlidingExpiration
/// By default, the sliding expiration is set for 14 days.
public MsalMemoryTokenCacheOptions()
{
- this.SlidingExpiration = TimeSpan.FromDays(14);
+ SlidingExpiration = TimeSpan.FromDays(14);
}
}
}
\ No newline at end of file
diff --git a/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs b/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs
index 7ad18082..53e088e5 100644
--- a/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs
+++ b/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs
@@ -60,18 +60,18 @@ private string GetCacheKey(bool isAppTokenCache)
}
else
{
- // In the case of Web Apps, the cache key is the user account Id, and the expectation is that AcquireTokenSilent
- // should return a token otherwise this might require a challenge
- // In the case Web APIs, the token cache key is a hash of the access token used to call the Web API
- JwtSecurityToken jwtSecurityToken = _httpContextAccessor.HttpContext.GetTokenUsedToCallWebAPI();
- return (jwtSecurityToken != null) ? jwtSecurityToken.RawSignature
- : _httpContextAccessor.HttpContext.User.GetMsalAccountId();
+ // In the case of Web Apps, the cache key is the user account Id, and the expectation is that AcquireTokenSilent
+ // should return a token otherwise this might require a challenge.
+ // In the case Web APIs, the token cache key is a hash of the access token used to call the Web API
+ JwtSecurityToken jwtSecurityToken = _httpContextAccessor.HttpContext.GetTokenUsedToCallWebAPI();
+ return (jwtSecurityToken != null) ? jwtSecurityToken.RawSignature
+ : _httpContextAccessor.HttpContext.User.GetMsalAccountId();
}
}
///
/// Raised AFTER MSAL added the new token in its in-memory copy of the cache.
- /// This notification is called every time MSAL accessed the cache, not just when a write took place:
+ /// This notification is called every time MSAL accesses the cache, not just when a write takes place:
/// If MSAL's current operation resulted in a cache change, the property TokenCacheNotificationArgs.HasStateChanged will be set to true.
/// If that is the case, we call the TokenCache.SerializeMsalV3() to get a binary blob representing the latest cache content – and persist it.
///
@@ -100,7 +100,7 @@ private async Task OnBeforeAccessAsync(TokenCacheNotificationArgs args)
}
}
- // if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
+ // if you want to ensure that no concurrent write takes place, use this notification to place a lock on the entry
protected virtual Task OnBeforeWriteAsync(TokenCacheNotificationArgs args)
{
return Task.CompletedTask;
@@ -108,7 +108,7 @@ protected virtual Task OnBeforeWriteAsync(TokenCacheNotificationArgs args)
public async Task ClearAsync()
{
- // This is here a user token cache
+ // This is a user token cache
await RemoveKeyAsync(GetCacheKey(false)).ConfigureAwait(false);
}
diff --git a/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs b/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs
index 6cafc227..2ee2f90c 100644
--- a/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs
+++ b/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs
@@ -5,7 +5,6 @@
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
-using Microsoft.Identity.Client;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
@@ -13,7 +12,7 @@
namespace Microsoft.Identity.Web.TokenCacheProviders.Session
{
///
- /// An implementation of token cache for Confidential clients backed by Http session.
+ /// An implementation of token cache for Confidential clients backed by an Http session.
///
/// For this session cache to work effectively the aspnetcore session has to be configured properly.
/// The latest guidance is provided at https://docs.microsoft.com/aspnet/core/fundamentals/app-state
@@ -33,9 +32,10 @@ public class MsalSessionTokenCacheProvider : MsalAbstractTokenCacheProvider, IMs
{
private HttpContext CurrentHttpContext => _httpContextAccessor.HttpContext;
- public MsalSessionTokenCacheProvider(IOptions azureAdOptions,
- IHttpContextAccessor httpContextAccessor) :
- base(azureAdOptions, httpContextAccessor)
+ public MsalSessionTokenCacheProvider(
+ IOptions azureAdOptions,
+ IHttpContextAccessor httpContextAccessor) :
+ base(azureAdOptions, httpContextAccessor)
{
}
@@ -46,8 +46,7 @@ protected override async Task ReadCacheBytesAsync(string cacheKey)
s_sessionLock.EnterReadLock();
try
{
- byte[] blob;
- if (CurrentHttpContext.Session.TryGetValue(cacheKey, out blob))
+ if (CurrentHttpContext.Session.TryGetValue(cacheKey, out byte[] blob))
{
Debug.WriteLine($"INFO: Deserializing session {CurrentHttpContext.Session.Id}, cacheId {cacheKey}");
}
@@ -97,11 +96,6 @@ protected override async Task RemoveKeyAsync(string cacheKey)
}
}
- ///
- /// The duration till the tokens are kept in memory cache. In production, a higher value , upto 90 days is recommended.
- ///
- private readonly DateTimeOffset cacheDuration = DateTimeOffset.Now.AddHours(12);
-
private static readonly ReaderWriterLockSlim s_sessionLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
}
diff --git a/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs b/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs
index 754e48e6..f465a7b9 100644
--- a/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs
+++ b/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs
@@ -50,7 +50,7 @@ public static IServiceCollection AddSessionTokenCaches(this IServiceCollection s
});
}
- services.AddHttpContextAccessor();;
+ services.AddHttpContextAccessor();
services.AddScoped();
return services;
diff --git a/Microsoft.Identity.Web/WebAppServiceCollectionExtensions.cs b/Microsoft.Identity.Web/WebAppServiceCollectionExtensions.cs
index 914bf48d..cc1a61a7 100644
--- a/Microsoft.Identity.Web/WebAppServiceCollectionExtensions.cs
+++ b/Microsoft.Identity.Web/WebAppServiceCollectionExtensions.cs
@@ -44,15 +44,15 @@ public static IServiceCollection AddSignIn(
services.Configure(AzureADDefaults.OpenIdScheme, options =>
{
// Per the code below, this application signs in users in any Work and School
- // accounts and any Microsoft Personal Accounts.
+ // account and any Microsoft personal account.
// If you want to direct Azure AD to restrict the users that can sign-in, change
// the tenant value of the appsettings.json file in the following way:
// - only Work and School accounts => 'organizations'
- // - only Microsoft Personal accounts => 'consumers'
- // - Work and School and Personal accounts => 'common'
- // If you want to restrict the users that can sign-in to only one tenant
+ // - only Microsoft personal accounts => 'consumers'
+ // - Work and School and personal accounts => 'common'
+ // If you want to restrict the users that can sign-in to only one tenant,
// set the tenant value in the appsettings.json file to the tenant ID
- // or domain of this organization
+ // or domain of that organization
options.Authority = options.Authority + "/v2.0/";
// If you want to restrict the users that can sign-in to several organizations
@@ -61,7 +61,7 @@ public static IServiceCollection AddSignIn(
options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.GetIssuerValidator(options.Authority).Validate;
// Set the nameClaimType to be preferred_username.
- // This change is needed because certain token claims from Azure AD V1 endpoint
+ // This change is needed because certain token claims from the Azure AD V1 endpoint
// (on which the original .NET core template is based) are different than Microsoft identity platform endpoint.
// For more details see [ID Tokens](https://docs.microsoft.com/azure/active-directory/develop/id-tokens)
// and [Access Tokens](https://docs.microsoft.com/azure/active-directory/develop/access-tokens)
@@ -111,7 +111,11 @@ public static IServiceCollection AddSignIn(
/// Service collection to which to add authentication
/// Initial scopes to request at sign-in
///
- public static IServiceCollection AddWebAppCallsProtectedWebApi(this IServiceCollection services, IConfiguration configuration, IEnumerable initialScopes, string configSectionName = "AzureAd")
+ public static IServiceCollection AddWebAppCallsProtectedWebApi(
+ this IServiceCollection services,
+ IConfiguration configuration,
+ IEnumerable initialScopes,
+ string configSectionName = "AzureAd")
{
// Ensure that configuration options for MSAL.NET, HttpContext accessor and the Token acquisition service
// (encapsulating MSAL.NET) are available through dependency injection
@@ -125,7 +129,7 @@ public static IServiceCollection AddWebAppCallsProtectedWebApi(this IServiceColl
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
// This scope is needed to get a refresh token when users sign-in with their Microsoft personal accounts
- // (it's required by MSAL.NET and automatically provided when users sign-in with work or school accounts)
+ // It's required by MSAL.NET and automatically provided when users sign-in with work or school accounts
options.Scope.Add(OidcConstants.ScopeOfflineAccess);
if (initialScopes != null)
{