In an article I wrote in 2018, I talked about Azure AD v2 and MSAL from a developer's point of view. At that time the v2 endpoint was still quite new and was lacking features that meant issues for application migration.

Since it's been a while, I thought I'd revisit the topic to see what has changed since then.

V2 endpoint

To recap, the v2 endpoint allows "converged authentication", i.e. users can use either their organizational Office 365 (Azure AD) accounts or their personal Microsoft Accounts (e.g. outlook.com). In contrast, the v1 endpoint only allows authentication with Azure AD accounts. Of course you were able to use personal Microsoft accounts then as well, but they had to be members of an Azure AD tenant. With v2 personal accounts can be used as is.

The Microsoft Graph API can be used with either type of account. So for an app which uses the MS Graph API, this allows it to use a single identity provider instead of having to support both organizational and personal accounts separately.

This hasn't really changed since I wrote the article two years ago.

App registration

Previously v2 applications were registered in a new portal, but as I noted in the older article:

Note that this is temporary! V2 endpoint-enabled apps will be manageable from the Azure Portal in the future!

The management of v2 applications is now done in the Azure Portal. There is also no such thing as a v1 app or a v2 app. All app registrations support both v1 and v2 endpoint.

Platforms

A large change in the "v2 application registration portal" was that you could specify platforms. This allows you to define your app in one registration, instead of having to do it in parts for the different parts of your application (mobile app, API etc.).

This is still true in that you can define redirect URIs for different platforms in the one app registration. So you can define the redirect URI for your mobile app under the Mobile and desktop application platform, and configure scopes exposed by the back-end API in the same app registration. All app registrations in the Azure Portal support this, so it isn't limited to "v2 apps".

Platform selection when adding redirect URIs

The Web platform previously included both single page applications (SPAs) and back-end Web apps, but now there is a separate SPA platform that allows usage of Authorization Code flow with PKCE from the front-end. You can still use the Web platform with the implicit flow for SPAs, but that is no longer the recommendation. To use the newer flow, your app should use MSAL.js 2.x instead of 1.x.

Scopes

This is one part that I think has not changed since the article two years ago. The v2 endpoint still uses the scope parameter instead of the resource parameter (which makes it more compliant with OpenID Connect spec). Let's say your app wants to read the user's calendars, you'd request the following scope:

scope=https://graph.microsoft.com/Calendars.Read

The structure of a scope identifier is essentially API identifier/Scope value. In this case https://graph.microsoft.com is the Graph API's identifier, and Calendars.Read is the scope value. With MS Graph API you can also use the short form:

scope=Calendars.Read

Note the above only works with MS Graph API, with everything else you need the full scope id.

When you specify the permissions your app needs like this, it allows something called incremental and dynamic consent which we will look at next.

Incremental and dynamic consent

One of the big features of the v2 endpoint, allowing apps to define permissions it needs at authentication time instead of ahead of time in the app registration. Especially great for multi-tenant apps where changes to the app registration are not propagated to the other tenants where the app is already registered. A new version of your app can say what permissions it now requires when the user is signing in, requiring them to give consent to any new permissions that weren't present previously.

You can also use this feature for optional features in your app, like an integration with the user's calendar. The app can request the Calendars.Read scope when the user wishes to enable the feature, so it is only requested if it is required.

If you do want the older behaviour, which is called static consent, you can use the special ".default" scope, e.g. https://graph.microsoft.com/.default. This will make AAD check the required permissions in your app registration like it used to with v1.

With client credentials flow, you need to use the ".default" scope always. Permissions for service to service calls must be defined ahead of time and an admin must consent to them.

Multi-tenancy requirement

In the older article, I mentioned that:

Another big difference to v1 is that currently all applications are multi-tenant. This will change later, allowing you to specify the target audience for your app.

You can now choose from four different audiences for the app when registering it:

App audience options: single-tenant, multi-tenant, multi-tenant and Microsoft accounts, only Microsoft accounts

The authority URLs are still the same and now match the above options:

  • https://login.microsoftonline.com/{tenant-id}/v2.0
    • Allow only a specific Azure AD tenant (single-tenant)
  • https://login.microsoftonline.com/organizations/v2.0
    • Allow only Azure AD/Office 365 accounts (multi-tenant)
  • https://login.microsoftonline.com/common/v2.0
    • Allows any account
  • https://login.microsoftonline.com/consumers/v2.0
    • Allow only personal MS accounts

Only OpenID Connect and OAuth

This also has not changed since the writing of the previous article. The v2 endpoint only supports the more modern OpenID Connect and OAuth protocols for authentication. WS-Federation and SAML are supported by the v1 endpoint.

What has changed is that the v2 endpoint now supports all of the OpenID Connect/OAuth flows that v1 did, including Device Profile and Resource Owner Password Credentials. This was a major limitation and I'm happy to see it fixed.

MSAL

The new library that replaced the older ADAL; Microsoft Authentication Library (MSAL) allows apps to integrate with the v2 endpoint. Two years ago, MSAL supported .NET, JavaScript and Android. The supported platforms now are:

The JavaScript version has also been updated to support the new Authorization Code flow with PKCE. The libraries are also mostly Generally Available now and thus fully supported for production use.

Limitations and problems

Previously, your app could only use a very limited set of APIs through the v2 endpoint. This is no longer the case. You can use any API through the v2 endpoint.

You can also register stand-alone APIs now. An app can totally use an API in another app registration.

Writing custom token caches is still done differently from ADAL, but it does now support asynchronous reading and writing of cache data. If you want to store user token cache data to e.g. a database, you need to set "BeforeAccess" and "AfterAccess" callbacks. The former is responsible for loading data and the latter saving the data.

var app = ConfidentialClientApplicationBuilder.Create("client-id")
  .WithTenantId("aad-tenant-id")
  .WithClientSecret("client-secret")
  .Build();
app.UserTokenCache.SetBeforeAccessAsync(async args =>
{
  // Load and deserialize data from cache
  string cacheKey = args.SuggestedCacheKey;

  byte[] data = // Load data from somewhere...
  args.TokenCache.DeserializeMsalV3(data);
});
app.UserTokenCache.SetAfterAccessAsync(async args =>
{
  // Serialize given data to cache
  string cacheKey = args.SuggestedCacheKey;
  byte[] data = args.TokenCache.SerializeMsalV3();
  // Write bytes...
});

There is now migration guidance available for applications, which didn't exist previously: https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-migration. One thing that I think the article didn't talk about a lot is that you can customize token cache deserialization (at least in .NET) to load ADAL format cache data if MSAL format data is not yet available for the user. This allows seamless migration and usage of existing token caches.

When to use v2

If you are registering a new app, absolutely use the v2 endpoint. Unless for some reason you really want to use SAML for authentication (why?). Existing apps can be migrated to take advantage of the new features, but the v1 endpoint still continues to work so you aren't in a hurry. In general I'd recommend migrating to v2.

Summary

The v2 endpoint is essentially at feature-parity with the v1 endpoint (except for the WS-Fed and SAML protocols), so I can definitely recommend its usage. Two years ago the situation was quite different with various limitations in place. It also felt like a work-in-progress. But it is certainly ready for production use now.