Using ADAL’s AcquireTokenBy AuthorizationCode to Call a Web API From a Web App
We are going to publish a sample doing justice to this scenario soon, but in the meanwhile I am getting questions about this multiple times per day hence I think it’s time to whip up a super-quick post and unblock some of you guys.
Wait, what am I talking about? Perhaps I rushed a bit into it let’s take a step back:
Say that you have a Web application. Say that as part of the functions it perform, your app needs to call a Web API. Say that such Web API is protected by a Windows Azure AD tenant. How do you obtain a token for it?
The answer is – via OAuth2, of course; and via ADAL, if you don’t want to write too much code.
You might have already seen how to use ADAL for obtaining tokens from native applications: the flow for Web applications is a little different.
Web apps are characterized in the OAuth2 spec as “confidential clients”, that is to say clients that can keep a secret: the idea is that what you save on your web server is not accessible to anybody else, hence you can safely save keys there. As such, during the token acquisition flow your app is required to use such a secret to identify itself. In practical terms, this means that when you create your app in the directory tenant you need to have a credential of some sort (a secret, a certificate, etc) assigned to it and later use it from your code. The good news? When you create one Web app with the new VS2013 ASP.NET templates, and you assign read or write directory access rights to it, the creation process itself will provision a secret for your app and will even make you the courtesy of saving it in your web.config, ready for you to use! That secret is put there so that your app can call the Graph API (through another flow, the client credential grant, but that’s a story for another day) but it will just as well for our scenario.
If you want to follow along, this would be a good time to drop in VS2013 and create a new Single Organization – cloud MVC app. Make sure you choose read or write in the bottom dropdown.
If the differences with the native client case would end here, things would be pretty easy; we’d just add to AcquireToken a parameter for passing the client secret and we’d be done. However differences do run a bit a deeper here.
In a native client the main app UI activity is well separated from the token acquisition flow, which takes place in a dedicated browser dialog; but for a Web app all the action takes place entirely in the browser! That means that if the user needs to interact with some external UI in order to grant to the Web app access to the Web API, he/she needs to be shipped out to the authority that renders the consent UI and come back with some artifact showing that consent has indeed been granted. Now, the example I am showing is super special and no UI needs to be actually shown – for 2 reasons:
- Currently the consent for accessing resources in Windows Azure AD is admin based – that means that if the tenant admin consented for one given app/resource to be provisioned in the tenant, direct user consent is not necessary (though user authentication is, given that the token will be issued on per-user basis)
- In this sample I am using the same AAD tenant for both web sign on and for protecting the target API – which means that when being redirected the user will land on the Authorization endpoint already authenticated, hence no UI will be shown.
I am doing this simplified scenario because it’s already 11:40PM and I can’t write this post all night, but in fact it’s perfectly possible for you to use a different tenant or even implement web sign on in completely different fashion, without even using Windows Azure AD. There would simply be more provisioning steps involved.
Despite the simplifications afforded by the above, the OAuth2 code grant still requires us to ship the user offsite to obtain an authorization code, retrieve that code once it comes back and use it to call AAD and obtain the necessary token(s).
That flow is heavily dependent on the stack you are using for developing your web app, hence it was not possible for us to wrap it in its entirety in a single call as we’ve done for the native clients. Rather, in ADAL this flow is split in two phases:
- You, the Web app developer, are responsible to initiate the process by redirecting the user to the Windows Azure AD tenant’s Authorization endpoint. It’s pretty straightforward, the parameters are pretty much the same you’d pass to the usual ADAL calls.
You are also responsible to set up a handler/page/action at the configured return URL to retrieve the authorization code - Once you have the code, you can pass it to ADAL along with the client id & secret to obtain an access token, refresh token etc etc as usual.
#1 is the part that is dependent on the development stack, hence it’s up to you to implement it in whatever way is appropriate for the tech you used. #2 is all automated goodness.
So let’s make that happen, shall we?
Navigate to your Windows Azure portal, select the app you create via VS, and click Configure. You’ll get to the screen below.
At the very bottom you’ll see a drop down listing all the Web API provisioned in your tenant (I’ll assume you have at least one; if you don’t, see any of the posts I’ve been publishing ion the last month and you’ll find instructions to create one). Pick the one you like best, then hit Save on the command bar below.
That done, move your attention to the Reply URL section just few lines above.
Go ahead and add a new URL, corresponding to the address on which you’ll want to add logic for handling the return flow carrying the code. Hit save again, then move back to VS2013.
Head to the HomeController, and spend a second to take a look to the list of constants placed there by the template. As mentioned, those are mostly for the benefit of the boilerplate Graph code included in the UserProfile action; but they’ll come in handy for us as well.
The first thing to add is the logic for triggering the token acquisition flow. Here I’ll just pick one of the default actions to host it. Here’s the code, formatted for your screens:
1: public ActionResult About()
2: {
3: string authorizationUrl = string.Format(
4: "https://login.windows.net/{0}/oauth2/authorize?
api-version=1.0&
response_type=code&
client_id={1}&
resource={2}&
redirect_uri={3}",
5: ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value,
6: AppPrincipalId,
7: "http://myadfsvagaries/webapi",
8: "https://localhost:44304/Home/CatchCode"
9: );
10:
11: return new RedirectResult(authorizationUrl);
12: }
The URL is just the standard URL you’ll see for any Authorization endpoint (apart for the resource parameters) but just for excess of clarity
- the base URL is the Windows Azure AD URL + the current tenant identifier (taken from the web sign on claim in line 5, but I could have kept it in config just as well) and the Authorize sub-url
- Line 6 carries the client id of the web app
- line 7 specifies the ID of the Web API we want to call
- line 8 contains the return URL from where we want to retrieve the code – this is the same URL we added in the portal
That done, we just need the code to retrieve the code and use it to get the token(s).
public ActionResult CatchCode(string code) { AuthenticationContext ac = new AuthenticationContext(string.Format("https://login.windows.net/{0}", ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value)); ClientCredential clcred = new ClientCredential(AppPrincipalId, AppKey); var ar= ac.AcquireTokenByAuthorizationCode(code, new Uri("https://localhost:44304/Home/CatchCode"), clcred); return View(); }
If you followed the other posts on ADAL, you should recognize the generic structure. First we create an AuthenticationContext for the current tenant; then we create a ClientCredential with the id and the secret of the Web app (same thing we’d do for calling the Graph).
The news here is the call not to AcquireToken, but to AcquireTokenByAuthorizationCode – passing the ClientCredential and a return URL (IMPORTANT – it must be the same return URL value used in the code request!).
The reason for the different name is to make it explicit that this is not exactly operating in the same way as the other primitives – apart from the calling pattern, for example, AcquireTokenByAuthorizationCode won’t save tokens in the cache.
Want to give it a spin? Try it! Put a breakpoint on the last line of CatchCode and hit F5. Go through the authentication, then click About. If everything goes well, you should get a nice AuthenticationResult. Let’s take a look at what the debugger tells us:
The main thing I wanted to show you is that the token you get contains claims describing the user, which is one of the main differentiators in respect to other server side flows like the client credentials flow provided OOB for Graph access in the template.
There you have it! This is a very messy and incomplete walkthrough – for example, I didn’t mention at all where you are going to save the tokens you just got – but as I mentioned a good & comprehensive sample is on its way. Hopefully this will help unblock you, feel free to get in touch if you need clarifications!