Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

AuthenticationContext the connection to Azure AD

Jean-Marc Prieur edited this page Jul 19, 2018 · 3 revisions

ADAL.NET, has one class representing a connection to Azure AD: AuthenticationContext.

What is AuthenticationContext?

An AuthenticationContext represents the authority you want to use for gaining access to resources (ie the authority you refer to when you need tokens). Contrary to MSAL, AuthenticationContext does not even represent an Azure AD v1.0 application: as you can see in the class diagram representation below ClientID (ApplicationID) of the application is not passed at the construction of this class, but needs to be passed in all (AcquireTokenXXX) requests, and sometimes even in the constructor of data structures. The AuthenticationContext is really:

  • a connection to the Security Token Service (STS) or authorization server , through the Authority.
  • and a token cache.

image

It might be useful to think of the Authority as the source of identities/tokens, in the business sense: I am getting tokens from Contoso. Now Contoso can choose to surface its issuing capacity as an ADFS instance, or as a cloud tenant. Examples of clouds are the Microsoft Cloud, national clouds like the German cloud, or the Chinese Cloud, or even sovereign clouds, like the US government cloud

Construction of an AuthenticationContext

image

  • All the constructors of AuthenticationContext take the authority URL as first parameter.
  • Overrides of the first constructor also enable application developers to:
    • By pass the authority validation (by setting the validateAuthority parameter to false)
    • Set their own token cache in cases where the application needs or wants to manage the token serialization itself. A token cache is provided by default, with serialization in some platforms. Serialization can be customized for .NET Framework and .NET Core and even needs to be customized in these platforms to ensure persistence of the token cache. [See more in paragraph about Broker on Android and iOS ]

Authority validation

The authority needs to be set to the URL to the STS. Examples of valid authority are:

  • https://login.microsoftonline.com/f31e6716-26e8-4651-b323-2563936b4163 for a single tenant application defined in the tenant which TenantId is f31e6716-26e8-4651-b323-2563936b4163
  • https://login.microsoftonline.com/contoso.onmicrosoft.com. This representation is like the previous one, but uses the tenant domain name instead of the tenant Id.
  • https://login.microsoftonline.de/contoso.de also uses a domain name, but in this case the Azure AD tenant admins have set a custom domain for their tenant. And this one is for the German national Cloud
  • https://login.microsoftonline.com/common in the case of a multi-tenant application, that is an application available in several Azure AD tenants
  • It can finally be an Active Directory Federation Services (ADFS) URL, which is recognized with the convention that the URL should contain adfs like https://contoso.com/adfs.

Note that the authority might also be an Azure AD B2C tenant, but ADAL does not support B2C.

Case when the authority is not known in advance.

As described in The Common Endpoint: Walks Like a Tenant, Talks Like a Tenant… But Is Not a Tenant "common" is a convention used to tell Azure AD “I don’t yet know which tenant should be used. Please render a generic credential gathering experience, and we’ll figure out the tenant depending on what account the user enters”. It's used, for example, for multi-tenant applications.

In the case where the application does not know the tenant in advance, the instanciation of the AuthenticationContext is done in the following way:

var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/common");
var authenticationResult = authenticationContext.AcquireTokenAsync( .... );

however, if you do only that, next time you call AcquireTokenSilentAsync, the cache won't be hit as you got an access token and a refresh token for the real tenant Id, and it was cached, whereas here you are requesting it for common. The right pattern to use in multi-tenant applications is to create a new AuthenticationContext with the authority containing the real tenant ID.

The code snippets below show the case of a UWP or Xamarin.iOS or Xamarin.Android application (where the cache is automatically serialized by ADAL.NET). In the case of .NET Framework or .NET Core you would have to deserialize the cache and pass it to the constructor of AuthenticationContext in step 1.

// Case where the application does not know yet which tenant to use yet.
// 1. Instantiate the cache with the common authority
string commonAuthority = "https://login.microsoftonline.com/common";
AuthenticationContext authenticationContext = new AuthenticationContext(commonAuthority);

// 2. Inspect the cache
var cacheElements = authenticationContext.TokenCache.ReadItems();
IEnumerable<string> authorities = cacheElements.Select(e => e.Authority).Distinct();

if (authorities.Any())
{
    // 3. Pick an authority. Note that some applications even handle multiple authorities
    // (think of mail apps for several accounts). In that case they could even 
    // instantiate several authentication contexts and get tokens for each
    string authority = authorities.First(); // for example
    authenticationContext = new AuthenticationContext(authority, authenticationContext.TokenCache);
}

// 3. Acquire a token
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(...);

// 4. In the case where there was no cached tokens yet, we did not do 3). The authority is still the common authority. 
// We need to re-instantiate an AuthenticationContext with the real (tenanted) authority
if (authenticationContext.Authority == commonAuthority)
{
    // We now know the tenant (it's in authenticationResult.Authority)
    authenticationContext = new AuthenticationContext(authenticationResult.Authority, authenticationContext.TokenCache);
}

Advanced note: Server driven aliases of authorities (ADAL.NET >= 3.18)

In the past, the Azure AD authority URL used to be https://login.windows.net. It has then changed to https://login.microsoftonline.com. Of course, there are still applications (for instance Office) which use the old base URL, whereas others use the new base URL. Azure AD maintains a dictionary of authority aliases and will both automatically redirect your application to https://login.microsoftonline.com and provide the same tokens for the aliases. This redirection had, in past versions of ADAL, the effect of triggering un-necessary sign-ins for users - multiple authentication prompts, possibly within the same application, and "islands of SSO" effects when multiple applications were involved. The root cause of this behavior is that the ADAL libraries were using the authority URL passed in the AuthenticationContext constructor as a key for the token cache and were not aware of this aliasing. To avoid un-necessary authentication user prompts, recent versions of ADAL (for .NET from ADAL.NET 3.18) start by downloading the authority aliases dictionary from the STS and then take them into account when building the token cache keys.

Other properties of AuthenticationContext

Authentication context exposes other properties in addition to an accessor to the already mentioned constructor's parameters (Authority, ValidateAuthority and TokenCache). Those are:

  • CorrelationId is a GUID that the application developers can set, and which will be passed through all the interactions with the STS and the Web APIs, as well as in logs and telemetry. This enables them to diagnose issues. This can also enable Microsoft to provide advanced support.

  • ExtendedLifeTimeEnabled is a Boolean that first party applications (read Office) can set to true in case when the STS has an outage, to be more resilient. Indeed, Azure AD returns the token with an expiration time, and also with an extended expiration time. The tokens are automatically refreshed by ADAL and MSAL when the time is more than the expiration time, except when ExtendedLifeTimeEnabled is true and the time is less than the extended expiration time. This goes in pair with Web APIs middleware which, when this extended life time is enabled, can accept slightly expired tokens.

Clone this wiki locally