Extract authentication parameters from WWW-Authenticate headers

Scenarios

Unauthenticated calls to a protected web API

A protected web API will send a HTTP 401 Unauthorized error when an incoming request is not fully authorized to access the resource. The response may also include a WWW-Authenticate header with a challenge - extra information specifying how to get a correct access token to this resource. The resource can return this error response when the request either has not included an authorization token or the token is invalid. The web API also returns a challenge if the access token is out-of-date (for example, the user needs to login again with multi-factor authentication). Given that web APIs are unable to have interaction with the user, they need to propagate back the request to the client using the information in a WWW-Authenticate header. The client app is responsible for extracting these claims and including them in the token request to the identity provider. This should trigger the UI for the user to re-login. Afterwards, the identity provider will return an up-to-date access token which should be included in a request to the web API.

Flow between web API and a client

To see an example, navigate to https://graph.microsoft.com/v1.0/me. Microsoft Graph will return an HTTP 401 Unauthorized error and the WWW-Authenticate header will specify the authorization URI where to get the token and the client ID of this resource.

HTTP 401; Unauthorized
WWW-Authenticate: Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", client_id="00000003-0000-0000-c000-000000000000"

Navigate to https://yourVault.vault.azure.net/secrets/CertName/CertVersion, to receive a header that looks like the following:

HTTP 401; Unauthorized
WWW-Authenticate: Bearer authorization="https://login.windows.net/yourTenantId", resource="https://vault.azure.net"

Continuous Access Evaluation

Continuous Access Evaluation(CAE) allows resources to continuously keep track of the user and app changes in Microsoft Entra ID and update its policies in a timely manner. Based on the changed policies, CAE-enabled web APIs will send a WWW-Authenticate header with the appropriate claims challenge. For details, see How to use Continuous Access Evaluation enabled APIs in your applications. The WWW-Authenticate header will have the following form:

HTTP 401; Unauthorized
WWW-Authenticate=Bearer
  authorization_uri="https://login.windows.net/common/oauth2/authorize",
  error="insufficient_claims",
  claims="eyJhY2Nlc3NfdG9rZW4iOnsibmJmIjp7ImVzc2VudGlhbCI6dHJ1ZSwgInZhbHVlIjoiMTYwNDEwNjY1MSJ9fX0="

Conditional Access authentication context

Conditional Access authentication context (CA auth context) allows you to apply granular policies to sensitive data and actions instead of just at the app level. CA auth context also relies on web APIs sending back a WWW-Authenticate header. For details about CA auth context, see:

The WWW-Authenticate header returned in a CA auth context scenario is similar to the one returned by CAE-enabled web APIs:

HTTP 401; Unauthorized
WWW-Authenticate=Bearer
  client_id="Resource GUID"
  authorization_uri="https://login.windows.net/common/oauth2/authorize",
  error="insufficient_claims",
  claims="eyJhY2Nlc3NfdG9rZW4iOnsibmJmIjp7ImVzc2VudGlhbCI6dHJ1ZSwgInZhbHVlIjoiMTYwNDEwNjY1MSJ9fX0="

Code examples

MSAL.NET

To process the claims challenge, the client application will look for an insufficient_claims error in the WWW-Authenticate header and extract the claims property. If the claims value is Base64 encoded, it must be decoded. The claims challenge should be in a JSON format. Lastly, pass this value into WithClaims(String) when acquiring a token. MSAL.NET provides a WwwAuthenticateParameters class to help in extracting the claims.

When making an unauthenticated call to a protected web API, call CreateFromAuthenticationResponseAsync passing in the URI of the resource. MSAL will make a request to the resource, extract, and return the values in the WWW-Authenticate header.

WwwAuthenticateParameters parameters = 
    await WwwAuthenticateParameters.CreateFromResourceResponseAsync("https://yourVault.vault.azure.net/secrets/secret/version");

IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
    .WithAuthority(parameters.Authority)     
    .Build();

// For details about token caching, see https://aka.ms/msal-net-token-cache-serialization .
app.AppTokenCache.SetCacheOptions(CacheOptions.EnableSharedCacheOptions);

AuthenticationResult authenticationResult = await app.AcquireTokenForClient(new[] {"scope") // You should already know the scope in advance.
    .WithClaims(parameters.Claims)
    .ExecuteAsync();

When calling a web API which supports Conditional Access or Continuous Access Evaluation, use GetClaimChallengeFromResponseHeaders(HttpResponseHeaders, String) to handle HTTP 401 Unauthorized responses.

using HttpRequestMessage httpRequestMessage = new HttpRequestMessage(
        new HttpMethod(httpMethod),
        apiUrl);

httpRequestMessage.Headers.Add(
                    "Authorization",
                    authenticationResult.CreateAuthorizationHeader());

HttpResponseMessage httpResponse = await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false);

if (httpResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
    string claims = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(httpResponse.Headers);
    // Acquire a new token with these claims
    // Call the web API again with the new token
}

// Handle a successful web API response.

Microsoft.Identity.Web

In web APIs that use Microsoft.Identity.Web, use ReplyForbiddenWithWwwAuthenticateHeader(IEnumerable<String>, MsalUiRequiredException, HttpResponse) method to send back an HTTP 401 Unauthorized response with a WWW-Authenticate header.

Information included by Microsoft.Identity.Web (including non-standard properties):

  • Consent URL (to help multi-tenant web API developers to provide a link that the tenant users or admins can use to consent for the web API to be installed in their tenant)
  • Claims (in the case of a claims challenge)
  • Scopes for the resource.
  • ProposedAction (i.e. "consent")

See also