Introducing ADAL JS v1
Less than 4 months ago I wrote at length about the first preview of ADAL JS, a new library meant to help you to take advantage of Azure AD to secure your SPA apps and consume Web API from JavaScript.
Since then we’ve been iterating on the library surface and architecture, ingesting your feedback and your numerous direct contributions. The library has been stable for few weeks now, hence we decided to make ADAL JS v1 generally available.
I am very, very excited about this release . If I’d have to summarize why, I can identify 3 main reasons:
- The SPA scenario was the last topology we didn’t fully support, and yet it’s one of the most handy app architectures out there. Now you can take ADAL JS and have a ball.
- Thanks to a unique combination of constrained scenario (SPA) and simplicity of the targeted platform (JavaScript and SPA stacks), this is probably the ADAL flavor to date that offers the most [functionality] bang for the [complexity] buck.
- We worked hard to polish this little guy, and we had the pleasure of getting great help from you guys along the way. The community involvement has been amazing.
For a quick overview of what we are releasing today, please head to the announcement post on the team blog. If you want to dig deeper, stay with me… and I’ll show you how deep the rabbit hole goes.
What Is ADAL JS
ADAL JS is a JavaScript library which offers you a super easy programming model for
- signing on Azure AD users in your Single Page Apps (SPAs)
- consuming directly from JavaScript Web APIs secured by Azure AD
You can find a high level intro in this video.
If you are using AngularJS we provide very convenient primitives in line with Angular’s model. However, you can use ADAL JS with any SPA stack – or no stack at all, as long as the architecture is SPA.
Using ADAL JS is very simple. It boils down to the following steps:
Adding a Reference to ADAL JS
Your app will need a reference to the ADAL JS library files. As it is customary for JS libraries, we support any style you like:
>You can get the bits from our CDN. If your app uses Angular.JS, you’ll need both of the files below:
https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js
https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal-angular.min.js
(non minified version here and here)
If you are not using angular, you just need the first file.
>You can use Bower.
Simply type
$ bower install adal-angular
>You can grab the source directly.
The adal.js source is here. The adal-angular.js source is here.
Initializing ADAL JS
Azure AD wants needs to know about your application before allowing users to request tokens for it. That means that you first need to register your app in the Azure AD directory containing the users you want to authenticate.
In the process, Azure AD will generate a unique identifier for your app. Such identifier must be used at authentication time, so that AAD can tell that the request comes from your application.
ADAL JS offers a very simple config structure to write down that identifier, plus the specific directory you want to work with. Once you have those values in there, ADAL will use them during authentication without any extra work on your part. It looks like the below:
adalProvider.init( { tenant: 'contoso.onmicrosoft.com', clientId: 'e9a5a8b6-8af7-4719-9821-0deef255f68e' }, $httpProvider );
More details on that later, this is just for giving you an idea of the amount of initialization code required.
Deciding When/How To Trigger Sign In/Out
Once you initialized ADAL JS, all that’s left is deciding which parts of your application require authentication.
If you are using Angular, this is as easy as adding a requireADLogin: true property to the routes you want to protect, and the right thing will happen automatically.
If you want to trigger sign in and sign out explicitly from your own functions, you can simply wire up calls to login() or logOut() – methods provided by ADAL’s default authentication service.
Those are the absolute basics. Let’s dig a bit deeper.
How ADAL JS Works
Even if you are already familiar with SPA applications, it is worth spending a moment to get on the same page about what we think of when we use the term “SPA” in the context of ADAL JS.
With “SPA“ we mean a very specific application architecture: one in which the application frontend is implemented via JavaScript, and all communications with the application backend take place via Web API calls. The backend can be implemented with any dev stack/run on any platform you like, as long as it is a Web API. Here there’s how a canonical SPA looks like:
The user navigates to one initial location, from where he/she downloads one starting page and a collection of JavaScript files, containing all of the application’s interaction logic.
As the user interact with the application frontent after that initial download, whenever the app requires to run logic (or acquire data) on the server the JS scripts perform REST calls to the Web API backend, sending and retrieving the required data. The same JS logic takes care of using the new data to drive the experience: display the new data to databinded HTML controls, give the illusion of navigation by programmatically rearranging the current view, and so on.
The key point is that after that initial (single) page load, all the traffic is performed through REST calls instead of full page postbacks.
That is what we mean with “SPA”. ADAL JS is optimized to make extra easy to secure an app built with that architecture.
ADAL JS is yet another script that sits in the frontend portion of your SPA. ADAL JS is made of two distinct layers, hosted in two different files:
Just as SPA architecture optimizes user experience and interaction in web applications by loading necessary resources once, the concept of buying Jardiance online streamlines the process of obtaining necessary medication. With online pharmacies, patients can acquire Jardiance with minimal hassle, avoiding frequent trips to physical stores. This parallels how SPA minimizes server requests, enhancing efficiency and user satisfaction. By facilitating easy access to Jardiance through online purchases, users can manage their diabetes more effectively, similar to how SPA enhances the user experience by efficiently managing data interactions and updates without reloading entire pages. This digital advancement in healthcare mirrors the technological improvements seen in web development, both aiming to simplify and improve the user’s experience and effectiveness of the service provided.
- adal.js (or adal.min.js)
This is the lowest level of the library, containing all the domain specific logic for crafting and parsing OAuth2 messages, maintain state by caching tokens, maintain tokens fresh, request extra tokens when needed, and more.
This is the part of the library that is the most similar to other flavors of ADAL on different platforms. Here you will find AuthenticationContext, AcquireToken and many other familiar constructs –which just happen to be implemented in JavaScript. - adal-angular.js (or adal-angular.min.js)
This part of the library is meant to be used in the context of Angular.JS applications. It contains primitives that are especially apt to blend in the Angular programming model, minimizing the amount of code that is necessary to add identity features while hiding almost all of the nitty gritty details they entail. Here you’ll find handy initialization structures, route extensions for triggering authentication on specific actions, interceptors that secure communications with the backed automatically, properties exposing attributes of the currently signed in users, and more high level goodness. I discussed the main components in this preview time post.
If you want to, you can write your very own adal-<stackofchoice>.js for your favorite library – we chose this architecture precisely for enabling you to do so, or for not burdening you with Angular primitives if you are working at a lower level.
The general ADAL flow is very easy when you code and witness it, so easy that it might leave you with the impression that some “magic” (in the bad sense of the word) is going on. Let’s dispel that notion by describing what happens in some details.
Requesting a Token
Once you feed ADAL JS your app coordinates (the identifier of your app and the AAD directory you want to work with), it waits for one of the triggers that will signal the need to initiate a user authentication flow.
Here there’s some under the hood action. Once the user performs one of the actions that trigger authentication (hit a route decorated with RequireADLogin:true or invoke a function that calls login()), ADAL JS:
- Retrieves from the init configuration the Azure AD tenant you intend to use for authentication; crafts the address of its corresponding OpenID Connect discovery document, retrieves it, and reads from it what is the URL that should be used for authenticating the user and request a token.
- Constructs the token request URL with the just retrieved URL and the application ClientID you provided; then redirects the browser session to the request URL.
[note] This is not very single page-y, given that the redirect drops all the JS castle you just built when lading the first app page. However at the moment there is no alternative: authentication often entails gathering credentials, hence Azure AD abhors being iFramed; popping out a full fledged browser window would be impractical on mobile devices. Hence, the only alternative remaining is the full page redirect, with its JS reload overhead. If you have another idea on how to solve this, let us know! - The user is presented with a sign in experience, and if necessary to a consent experience, too. If all goes well, the user is redirected back to the application, carrying the requested token. This all happens using the OAuth2 implicit grant, which I describe here. This flow is specifically designed to return the token to the browser itself (via a # fragment).
[note] from the AAD perspective, both the JS component and the backend API correspond to the same application entry. As such, in this request the application is asking for a token for itself! In Azure AD this is possible only if the requested token is an id_token, hence that’s what the request asks for. This note will come in useful later. - The app single page and all its JS castle are reloaded in the browser. As it wakes up, ADAL JS finds the requested token, saves it in its token cache (which can be both in localStorage or sessionStorage, depending on your preference) and flips the switch that declares the current user authenticated. Furthermore, it parses the incoming token to extract the current user info and expose them to the app (for display purposes or similar functions)
Accessing the Backend
At this point, the user might think that the sign in concluded; but we are not quite there yet.
So far we only proved that the user came back with bits that look like a token in the right place, but we have no clue on whether those bits do correspond to a token we like. ADAL JS itself does not validate the token: it relies on the Web API backend to do so, hence until we don’t call the backed at least once we don’t really know for sure if the user obtained an acceptable token.
The good news are that the Web API was meant to validate that token anyway. Although the high level reason for which we obtained a token was for signing in the user, the way in which we implemented it was to ask for a token for accessing our own backend API. Using that token for securely accessing the API means attaching that token in the authorization header in every call to that API, as dictated by the OAuth2 bearer token specs.
Here there’s how it happens.
- The app performs a call to its backend API, asking for whatever data it needs. ADAL JS constantly listens for outgoing requests, via an interceptor: as soon as it detects a request toward the app’s own backend, it retrieves the id_token from the cache and attaches it to the request.
- The Web API receives the request. The API will be façaded by some middleware that retrieves the token from the request and validates it. In our samples we use the OWIN OAuth2 bearer token middleware, but you can use any library understanding the JWT format. If the token is deemed valid, the request is fulfilled. Note that this initial request is in no way special! ALL interactions with the Web API will look like this, in true stateless fashion.
[Note] our samples go in the details of this, but to give you a headsup. A Web API used as a SPA backend should expect from its frontend tokens whose audience is the clientID of the app’s entry in Azure AD. This is an artifact of the token being an id_token in this case. I am highlighting this because in the general case, Web API expect tokens from any client and the expected audience is what Azure AD calls the App Id Uri instead. - A successful response indicates that the backend was happy with the token, hence we can carry on. A failure would indicate the need of considering the current sign in moot and restart.
This is probably where ADAL JS departs the most from its .NET/iOS/Android brethren. All other ADALs concern themselves exclusively with token acquisition, mostly because they have no a priori information about the circumstances in which the tokens should be used and adding functionalities there would be equivalent to add unwarranted constraints (remember the WCF channels?).
ADAL JS can afford to go as far as attaching the right token to Web API calls because of strong hypotheses we make around the application’s architecture – specifically, about the way in which SPAs frontends talk to Web API. That extra knowledge allows us to give you a simpler programing model. Yay!
Renewing Tokens
I simplified things for the sake of clarity, but the above is not entirely accurate. When ADAL JS detects that a request is about to go out and it’s time to attach a token to it, ADAL doesn’t simply retrieve what’s in the cache and attach it. Rather, it examines its projected expiration time (saved at the time of the token acquisition) and if the token is no longer valid or just about to expire, it attempts to obtain a new one. How? I described this at length here: to summarize, ADAL JS uses an invisible iFrame to send a new token request to Azure AD. If the user is still in an active session with Azure AD (== there is a valid cookie) then the request will succeed, the cached token will be replaced by a new one, and the request will go out with that same spank new token with the user remaining blissfully unaware that a renewal took place.
If the user is NOT in such a session, then the request cannot succeed without user interaction – which clearly cannot take place in a hidden iFrame. ADAL blocks the call and raises a failure event, which you can handle as you see fit in your app logic. A typical strategy would be to trigger a new sign in.
Invoking External Web APIs via CORS
We are almost done! There is one last important scenario ADAL JS enables that I really want to mention.
Say that you want to enable your frontend to consume Web APIs that are not hosted in your own backend: APIs exposed by other developers, or even your own API that happen to be hosted on a domain that is different from the domain serving your SPA files. I am of course assuming that those new API also accept Azure AD tokens. I am also assuming that those API support CORS or equivalent mechanism for allowing cross origin script calls.
Good news! The mechanisms described above for intercepting outgoing requests and requesting tokens via hidden iFrame work just as well when applied to external APIs.
ADAL JS offers you the opportunity of declaring at init time a collection (the Endpoints structure) of the URLs of all the Web API you want to invoke. For each of those, you are also required to declare the App Id URI which which Azure AD identifies all those APIs.
When the interceptor detects a request toward one of those URLs, it looks up in the cache a token with the corresponding App Id URI. If it finds it, it attaches it. If it does not find it, or if it is present but expired, ADAL JS uses the usual hidden iFrame to perform a request for such a token (this time an access token!). Upon success, it caches it and uses it just like it did for calls to its own backend; upon failure, it raises similar events to notify the caller.
To summarize: thanks to the machinery we’ve put in place for dealing with calls to our own backed (again, please refer to this for details), we got the ability of invoking external APIs (almost) for free.
Samples
All the features and flows I described so far are demonstrated in a set of samples, which we released or updated today. Here there’s a quick jumplist.
Sign In with Angular
https://github.com/AzureADSamples/SinglePageApp-DotNet
This is pretty much the same basic ToDo sample we published during the preview, updated to reflect the new object model in v1. I shows you the minimal amount of code for exercising the basic sign in features of ADAL JS. It also shows you how to secure an ASP.NET Web API backend with OWIN mw in case you are expecting an id_token.
Calling API via CORS
https://github.com/AzureADSamples/SinglePageApp-WebAPI-AngularJS-DotNet
I am so, so happy to be able to finally point people to this sample!
The most common question we’ve got during the preview period was – “how do I use ADAL JS to call an API via CORS?”.
The ADAL JS repo readme does have some indications, but we know that nothing beats one sample with detailed instructions. So here you are: this sample is a clone of the first one, with one extra ASP.NET Web API (TGo) called via CORS.
The important things to notice form the frontend standpoint are the magic CORS commands in toGoListSvc.js (nothing to do with ADAL JS, this just seems to be a general point of confusion with CORS) and the endpoints structure in app.js, always remembering the explanation I gave earlier about how external API calls work on the basis of the info in there.
Sign In with JS/JQuery
https://github.com/AzureADSamples/SinglePageApp-jQuery-DotNet
This sample is meant to demonstrate the use of the low level ADAL JS API. If you’ll find the code a bit artificial, that’s because it is: it is not very realistic to expect a developer to rewrite a SPA stack by hand, instead of using Angular, React or similar.
We were very intentional about this (kudos to Danny for the patience demonstrated!) because we wanted to give you a baseline sample that shows how to use the ADAL JS primitives for common tasks directly, without mixing them with Angular artifacts and without forcing you to go through all adal.js code.
I want to come clean here: one of my big hopes in releasing this is that this sample will inspire you to write a adal-<myfavoritelibrary>.js binding and contribute it back to the community
JavaScript Frontend+ JavaScript Backend
I have been spending quite some time chatting with Mat Velloso about SPAs, ADAL JS and how to validate tokens on Web API. Tuesday morning I was in the office that Mat shares with Elliot, scribbling on their whiteboard how a Node JS Web API token validation via Simple-jwt could look like – and how awesome it would be to have a Node backend sample ready by ADAL JS v1 launch!
Little did I know that on Tuesday night I’d receive a mail from Mat saying that he already put together a PoC Amazing, right? We iterated on a couple of details, and you can see the results in https://github.com/matvelloso/AADNodeJWT – an app that is 100% JavaScript both on the frontend and the backend – with a simple but functional JWT validator that gets keys and issuer value directly from AAD discovery document. Very, very nice.
Thanks
Just four months ago, at the question “How can I protect a SPA with Azure AD?” I had to reply “You can’t”.
Today we are announcing the v1 of a full fledged library that does that, and more.
Those kind of feats don’t happen by themselves, I assure you. ADAL JS is the result of the relentless efforts of people like Omer Cansizoglu, the engineer who wrote and designed the bulk of ADAL JS; Danny Strockis, who wrote most of the samples; Mat Velloso, who gave lots of feedback and contributed to samples; and many others. But in fact, you know who else deserves credit? YOU. In less than 4 months of existence on Github, ADAL JS benefitted from many contributions and was the recipient of a lot of great feedback, which made a huge difference in the final shape of the product. In particular, thanks to DanWahlin, BartVDACodeware, BenGale, brianyingling, cicorias, manospasj, SPDoctor, ThorstenHans and zachcarroll for your contributions. I hope you are satisfied with how ADAL JS came out, and I can’t wait to see what you will achieve with it Happy coding!