- Blog
#Azure #Technology
Securing Azure Virtual Machines: Using Azure Bastion and Just-In-Time (JIT) Access
- 18/11/2024
Reading time 5 minutes
The Azure Active Directory v2 endpoint was published last year, and in this article we will try to piece together what it is, how it differs from v1, and what it can be used for.
The v2 endpoint allows, what Microsoft calls, converged authentication.
It provides some new capabilities, most notably the ability to authenticate using either:
The Microsoft Graph API can be used with either type of account. So for an app which uses the MS Graph API, this can be a great thing.
When using the v1 endpoint, applications would need to be registered in Azure AD by e.g. using the Azure Portal.
With v2, you need to use a separate portal, which can be found here: https://apps.dev.microsoft.com/.
Note that this is temporary! V2 endpoint-enabled apps will be manageable from the Azure Portal in the future!
You can use either a personal MS account or organizational account to register applications. The difference is that apps created with an organizational account will be registered in that user’s home tenant. This means users from the same tenant can see and modify the application as well (as long as they are added as owners on the app). Applications registered with a personal account can only be seen by that user.
So the lesson here is: If making software in an organization, use your organizational account to log in to the registration portal.
In v2 you do not choose a platform for the app like in v1. Instead, you can add platforms to an app.
The Web platform now includes both front-end Single Page Applications and back-end applications. If you are making a mobile application (or any app that runs on the user’s device, excl. SPAs), that would be a Native Application. Any back-end APIs in your app can be defined as Web APIs. You can define the permission scopes they offer as well.
This is actually quite a great thing, since in v1 you would either have to create a separate app for each part (which is best practice), or share one identity for all parts of the app (which you could not do if you had an API and a native app).
When requesting an access token from the v1 endpoint, you would have to specify a resource in the request. This resource parameter identifies the API we want to get a token for. For example, the Microsoft Graph API’s resource URI is https://graph.microsoft.com
. This parameter is actually not compliant with the OpenID Connect specification however. Client SDKs which have been designed with Azure AD in mind would allow you to specify it. Any other common SDKs and tools will not work.
In v2, the resource parameter is replaced by the scope parameter. This OpenID Connect-compliant parameter is still used to specify what API you would like to call. But it also allows you to specify which permissions/scopes your application needs. So for example, let’s say we want to read the user’s calendar events from the MS Graph API. Here is how we would specify that:
scope=https://graph.microsoft.com/Calendars.Read
The fully qualified name for a scope is composed of the application Id URI (e.g. https://graph.microsoft.com
) and the permission we want (e.g. Calendars.Read
). You can specify multiple scopes by separating them with spaces. Since an access token is only ever valid on one API, you can only specify scopes for one API in a token request. Normally you need to fully qualify every scope, but MS Graph API is a special case. It allows you to use the “short form”:
scope=Calendars.Read
This added ability of defining the necessary permissions is a nice segue to the next topic.
One of the biggest issues with v1, especially for multi-tenant applications, is that you must define every permission your app will ever need in advance. And the user must accept all of these required permissions. So for example, if your application offers an optional calendar integration to Office 365, you would have to require the access to the user’s calendar even if your app never used it for that user. There are ways around that by using a second application of course. With v2, you can specify which scopes you need when redirecting the user to authenticate.
This means you do not have to define which scopes your app needs beforehand, but can specify them at run-time. So now if the user wanted to enable the calendar integration, we could redirect them again to authenticate with the added scope! This combined with the one app, multiple platforms idea are perhaps the best parts of the v2 endpoint.
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. This means a user with a personal MS account or an account in any Azure AD tenant can sign in to your app. Now if you do not want this, you can restrict the types available by modifying the authority URL.
https://login.microsoftonline.com/common/v2.0
https://login.microsoftonline.com/organizations/v2.0
https://login.microsoftonline.com/consumers/v2.0
https://login.microsoftonline.com/{tenant-id}/v2.0
But of course the user can modify this URL, so you can’t rely on it purely. You would also need to check the tenant id from the user’s id token to see that it matches your expectations. The tenant id for personal Microsoft accounts is always the same: 9188040d-6c67-4c5b-b112-36a304b66dad
. A setting will be coming later, allowing us to specify the target audience for the app. This will also allow single-tenant scenarios.
The v2 endpoint only supports the OpenID Connect and OAuth protocols, which are very commonly used by modern applications. It does not support all of the flows for OAuth which v1 supported yet though, like Device Profile and Resource Owner Password Credentials Grant. Those flows will be enabled later. SAML and WS-Federation are protocols used by primarily older applications and were supported in the v1 endpoint, but are not supported in v2 (not yet at least).
If you have developed apps against the v1 endpoint in the past, you would probably be familiar with ADAL (Azure AD authentication Library). Since the v2 endpoint has changed significantly enough, Microsoft decided to make a separate library for the endpoint entirely. This new library is the Microsoft Authentication Library (MSAL).
Currently versions of the library exist for .NET (MSAL.NET), JavaScript (MSAL.JS), and Android (MSAL for Android). The JavaScript version is made in TypeScript, and can also be used as an ES5/ES6 module. The API has changed quite a bit, here is an example of acquiring an access token with the Authorization Code flow using the .NET version:
//Get signed in user ID string signedInUserID = context.Ticket.Principal.FindFirst(ClaimTypes.NameIdentifier).Value; //Create token cache for user TokenCache userTokenCache = new MSALSessionCache(signedInUserID, context.HttpContext).GetMsalCacheInstance(); //Create the object used to acquire tokens var cca = new ConfidentialClientApplication(AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null); //Get access token (and Id token) AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, AzureAdB2COptions.ApiScopes.Split(' ')); context.HandleCodeRedemption(result.AccessToken, result.IdToken);
The main difference is that with ADAL you would use an AuthenticationContext
to acquire tokens, whereas in MSAL you use ConfidentialClientApplication
or UserAgentApplication
/PublicClientApplication
, depending on if the application is running in a back-end or on the user’s device. Do note that all MSAL versions are in “Production-ready preview” at time of writing. So they do offer full support for the libraries, but they are still a work-in-progress.
In this part we will look at some limitations of the v2 endpoint as well as problems we have faced. These limitations are going to be removed as time goes by though! No official schedule exists for when those features will come. But they will be added.
Perhaps the biggest limitation currently is the rather small set of APIs that apps can use. Your app can use:
If you want to use any other API, then currently your only option is to use the v1 endpoint.
Also, you cannot build stand-alone Web APIs currently. Only an app with the same application ID can request an access token for the API. So you cannot register an API and use it from another app currently.
If you want to read about the full set of current limitations, you can check the documentation: Azure AD v2 endpoint limitations.
The API for token caches in MSAL.NET is a little bit funky. Firstly, the TokenCache
class is sealed
, so you can’t inherit from it as in ADAL. The only way of doing it properly is to instantiate a TokenCache
and set a couple event handlers that will be called to load and persist cache data. Now this would not be such a bad thing, but the handler methods must return void. What this means is that we cannot use asynchronous APIs to load and persist data in token caches. In ASP.NET Core applications with enough requests coming in, this could actually lead to the application going down and requiring a server restart to recover. The issue tracking the status of this problem can be found on GitHub.
Here is a small snippet from a token cache class showing the important bits with things like logging removed:
public TokenCache GetMsalCache() { //Cache already instantiated as _cache = new TokenCache(); _cache.SetBeforeAccess(BeforeAccessNotification); _cache.SetAfterAccess(AfterAccessNotification); return _cache; } private void BeforeAccessNotification(TokenCacheNotificationArgs _) { byte[] cacheData = _distributedCache.Get(_cacheKey); if (cacheData != null) { _cache.Deserialize(_protector.Unprotect(cacheData)); } } private void AfterAccessNotification(TokenCacheNotificationArgs args) { if (_cache.HasStateChanged) { try { _distributedCache.Set(_cacheKey, _protector.Protect(_cache.Serialize())); } catch (Exception e) { throw; } _cache.HasStateChanged = false; } }
So now we cannot take advantage of the asynchronous APIs available on the distributed cache, and we are blocking the thread until we get a response from the cache. This same issue exists in ADAL as well.
It is also important to remember that v1 applications are currently not compatible with the v2 endpoint. Same goes the other way, you cannot use the v1 endpoint from a v2 application. A migration path for v1 applications does not exist yet. However v2 application management is planned to be merged with v1 application management in Azure Portal. Once that happens, current v1 applications will be able to use the v2 endpoint, and there will be a documented migration path.
One problem that we run into some time ago, but did not run into anymore, was that consent was not being granted after logging in and consenting to the permissions. It took a while (like 15 seconds) for the consent to be done. This issue seems to have been fixed.
At the moment the v2 endpoint is really best suited for applications which:
For most other scenarios, Azure AD v1 is still the better one. Microsoft recommends using v1 for applications which only want to get authentication for Azure AD/Office 365 users. Once the endpoint develops and gets more of the v1 endpoint’s features, it will be the best choice for new applications.
The v2 endpoint for Azure AD has some really nice ideas. Incremental consent and the ability to define platforms for an app are really great features. It is still a work-in-progress though. But Microsoft is continuously improving it, and more features from v1 will be added as time goes on.
Our newsletters contain stuff our crew is interested in: the articles we read, Azure news, Zure job opportunities, and so forth.
Please let us know what kind of content you are most interested about. Thank you!