Getting an Azure Access Token for a Web Application Entirely in Code

UPDATE 1/13/2016:  The Azure and/or ADAL teams have made an unannounced change to purposely break this functionality.  This is clearly a problem for those providing and provisioning SaaS offerings in a variety of scenarios, but they have chosen to make this change without input.  If you would like to provide your feedback on this you can contact the responsible Program Manager directly at vbertocci@microsoft.com.

I generally find using Azure Active Directory for securing my resources to be a joyous thing, but the simplicity of use is pretty much vastly overstated by the marketing folks at Microsoft. I’ve used it quite a bit and yet still find myself simultaneously in seemingly uncharted and undocumented waters. As is unfortunately a little too common, I found myself in a spot where I really thought I was stuck the other day trying to get an access token for a specific user to a specific resource. I don’t think the scenario is really that uncommon so thought best to share.

The gist of this scenario is, I have an application defined in Azure Active Directory. It’s configured as a web application. That means that you *must* provide the application’s client secret when you request an access token to that application. The “standard” way to do this is to request an authorization code, and then you use the authorization code to get an access token. Okay, fundamentally I can do that and it won’t kill me.   The problem however is the really bad assumption, in my opinion, that you are going to have a human at the wheel, sitting at a browser and driving this thing around. That’s exactly how the process works in this case – users gets redirected to obtain the authorization code, they sign into Azure AD, they consent to whatever permissions the application is configured to use, and then the browser is redirected back again. You end up in some server side code plucking out authorization code from the query string and then using the Active Directory Authentication Library (ADAL) you call it’s AcquireTokenByAuthorizationCode to get your access token.

Okay that will work…as long as the human is sitting there driving. So what happens when the human is absent, and you want to get an access token for that person? Well, one of the ways you can get an access token from an application that is defined as a Native Application is to stick a username and password into a UserCredential and call the AcquireToken method in ADAL. Now I’m not suggesting that everyone should be storing usernames and passwords anywhere (and in fact in most cases I specifically go out of my way to avoid it). However there are certain cases, like where you are writing code that always runs as a service account, or you’re doing some scripting of new users and adding them to applications or application features, etc. Yeah, it’s a legit scenario (otherwise ADAL wouldn’t support this to begin with).

The problem is that while you can take that approach with a Native Application, it won’t work for a Web Application. A Web Application also requires the application’s client secret as explained above. Unfortunately there isn’t an overload in ADAL that supports both the UserCredential and client secret. I thought I was in a no win situation here when I came across this, but managed to work my way out of it so I thought I would share the approach I used. I do end up with an access token when I’m done, and I get it by providing a username, and a password, AND a client secret. I just don’t have to do the whole “drive this through a browser” thing to make it work.

The solution to this problem is that you’ll end up having to go outside of ADAL to get your access token. Instead you’ll need to make a post directly to the Graph API authorization endpoint to ask for your access token. When you do that, you can include whatever form values you want when you do your post. That ends up being the way to get your access token. Here’s a little code to illustrate, and then I’ll follow with some explanation.

//create the collection of values to send to the POST

List<KeyValuePair<string, string>> vals = new List<KeyValuePair<string, string>>();

vals.Add(new KeyValuePair<string, string>(“grant_type”, “password”));

vals.Add(new KeyValuePair<string, string>(“scope”, “openid”));

vals.Add(new KeyValuePair<string, string>(“resource”, ResourceUri));

vals.Add(new KeyValuePair<string, string>(“client_id”, ClientId));

vals.Add(new KeyValuePair<string, string>(“client_secret”, ClientSecret));

vals.Add(new KeyValuePair<string, string>(“username”, Username));

vals.Add(new KeyValuePair<string, string>(“password”, Password));

//create the post Url

//https://login.windows.net/8864cb2f-031a-5c22-fa2d-13d1cf4cb7dd/oauth2/token

string url = string.Format(“https://login.windows.net/{0}/oauth2/token “, TenantId);

//make the request

HttpClient hc = new HttpClient();

//form encode the data we’re going to POST

HttpContent content = new FormUrlEncodedContent(vals);

//plug in the post body

HttpResponseMessage hrm = hc.PostAsync(url, content).Result;

if (hrm.IsSuccessStatusCode)

{

//get the stream

Stream data = await hrm.Content.ReadAsStreamAsync();

}

So as you can see I’m creating a set of form values to send to the oauth endpoint, and I’m doing my post, and if it is successful, I’m reading the contents out into a stream in this case. The rest of the code that is less interesting is where I take that stream and serialize it into a class so I can easily refer to the access token, the refresh token, the expiration, etc. The key to making this work is to understand the various form key/value pairs. This is the “seemingly undocumented” piece I was describing above. You’ll find some documentation on MSDN about this at https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx. Since they only want to focus on the authorization code flow there there, you won’t find a complete listing of all the possible form post keys and possible values of each. Booo!!! Since I don’t have that, I’ll just document for you from my working code above, what those form values represent:

Key Value
resource The resource you are trying to obtain an access token for. If you are trying to access another Azure AD application, then you would use the APP ID URI here. If you are accessing something like Exchange Online, you would use it’s resource URI (which is https://outlook.office365.com/ for those of you following at home).
client_id This is the Client ID of the Azure application you are getting the access token for.
client_secret This is the Client Secret of the Azure application you are getting the access token for.
username This is the name of the Azure AD user for whom you are getting the access token.
password This is the password for the Azure AD user for whom you are getting the access token.
TenantId This is the ID (i.e. GUID) of the Azure Active Directory instance in which the Azure AD user is located.

Calling directly to the token endpoint in the Graph API to obtain an access token is pretty powerful really. I really don’t like resorting to that and only have this time because ADAL just didn’t cover my use case. It would be, dare I say, “idyllic” if someone would actually document all of the values you can throw up there (and/or make it easy to find, because I could not do that despite the indexing power of Bing). Meanwhile, this ends up being a nice way to get the token when you find yourself in this scenario.

Advertisements

How to Fix the OpenId Access Denied When User Won’t Grant Rights at Login

Okay, so the title may not be the clearest thing ever here today, but it’s tough to do in just a few words, so let me explain the scenario a little more fully.  Suppose you create an ASP.NET application and you configure it to be secured by Azure Active Directory.  When you do that you have to configure your right to request Azure AD permissions to sign-on and read the user’s profile.  This is the minimum right needed to have someone use Azure AD to login to your application, so naturally everyone will agree to this, right??  🙂

Well, as you can probably guess from this post, not always.  So what happens when a user sees that consent page from Azure AD at login time and then decides no, I don’t want to let you sign me in, so they hit cancel?  Well the out of the box behavior is that you get an unhandled exception in your ASP.NET application.  This of course brings up the awesome yellow screen of indecipherable death.  If you’re running it locally you can at least see the error message, which looks something like this:

So, how to fix right?  Well try as I might, the Bing Gods were not with me this day when I decided to try and figure this out. In fact for future search engine happiness, the error is access_denied and comes from Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolException. With a little trial and error I was able to figure out the way to fix this issue so wanted to document here for those of you stuck in a similar boat.

What you need to do is go back to your Startup.Auth.cs file.  You should have something configured in there for OpenIdConnect that starts out something like this:

app.UseOpenIdConnectAuthentication(

new OpenIdConnectAuthenticationOptions

What you want to do is configure one of the NotificationOptions, which you configure inside the OpenIdConnectAuthenticationOptions like this:

Notifications = new OpenIdConnectAuthenticationNotifications()

{

To deal with the scenario of someone canceling out of granting permissions during login you need to add a handler for the AuthenticationFailed notification.  Here’s what mine looks like:

AuthenticationFailed = (context) =>

{

//this section added to handle scenario where user logs in, but cancels consenting to rights to read directory profile

string appBaseUrl = context.Request.Scheme + “://” + context.Request.Host + context.Request.PathBase;

context.ProtocolMessage.RedirectUri = appBaseUrl + “/”;

//this is where the magic happens

context.HandleResponse();

context.Response.Redirect(context.ProtocolMessage.RedirectUri);

return Task.FromResult(0);

}

Essentially what’s happening there is if someone cancels it hits this notification handler.  I just figure out what the root Url of my application is, which I’ve pushed into the context.ProtocolMessage.RedirectUri property (which I actually liberally stole from my handler for RedirectToIdentityProvider).  Then I redirect somewhere else in my site that doesn’t require authentication, which in this case is my home page.

That’s it.  I don’t really see this covered in any of the sample code locations I usually hit up for Azure AD code so thought you might find it useful.

 

OneDriveBrowser and o365 APIs with A Custom Persistent Store for ADAL Token Cache

In this post I’m going to briefly cover a custom token cache that I wrote for use with ADAL.  The implementation itself is pretty straightforward from a coding perspective so I will just highlight a few of the basics.  What has been less clear up to this point is the “right way” to use it in your apps to make sure that you’re cached tokens are being used correctly, so I’ll cover that as well.  The token cache code itself is based on the general outline of the capabilities as Vittorio described in this blog post:  http://www.cloudidentity.com/blog/2014/07/09/the-new-token-cache-in-adal-v2/.  The sample application I’m using is an updated version of the OneDriveBrowser built on the o365 APIs that I originally covered here:  http://blogs.technet.com/b/speschka/archive/2015/01/05/onedrive-for-business-browser-using-o365-apis.aspx.

Coding Implementation

The code itself is pretty straightforward.  To begin with I created a new project and added the ADAL v2 Nuget package.  I then created a new class and had it inherit from Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache.  In my implementation I’m storing the tokens in Azure table storage.  I’m using it in an ASP.NET MVC application, and I need to track the tokens on a per user basis.  In my case the main customizations then that I need to account for are a) tracking tokens for individual users and b) managing access to Azure storage.  I provide hooks to both of those things through my constructor.

For tracking individual users I’ve used the user UPN.  I’ve configured my MVC app so that it’s secured with Azure Active Directory.  Since a user has to authenticate before they even get into my web app, I can be assured that they have a UPN.  For managing access to Azure storage I left in a couple of options.  I have the storage name and key included in one of the helper classes in my custom TokenCache project.  That way if you just want to take the code and compile it yourself, you can replace those values with the storage name and key that you are using.  As another option, I created a second constructor that takes the storage name and key in addition to UPN so you can set your credentials on the fly.  Here’s an example of what the two constructors look like (my class name is TokenStore):

 

public TokenStore(string UPN)

public TokenStore(string UPN, string storageName, string storagePassword)

 

Inside the class I’ve implemented BeforeAccessNotification, AfterAccessNotification, and DeleteItem.  The notifications are hooked up from my constructors with code like this:

this.BeforeAccess = BeforeAccessNotification;

this.AfterAccess = AfterAccessNotification;

 

DeleteItem doesn’t have an event handler to hook to so in that case I just have to override it, invoke the base class method first, then do my stuff.  Again, the actual code for all of this is pretty simple.  I created a helper class to manage all of the Azure stuff, so in pseudo code terms my implementations look like this:

  • BeforeAccess:  use the UPN that was passed into the constructor and the resource ID that is being requested.  Look in Azure storage to see if I have a token in there for that combination; if so, then get the byte array out of table storage and call the Deserialize method that comes from the base class.

  • AfterAccess:  look to see if the cache was updated (for example, if the access token was refreshed).  If so, save the byte array back to table storage and set the HasStateChanged property of my token cache to false so that it doesn’t keep trying to overwrite the same token.

  • DeleteItem:  call the base class so the deleted token is removed from the in-memory cache, then delete the same item out of Azure table storage.

 

That’s basically it.  All of the source code is included with this post so you can review it and use it as you see fit.

App Implementation

As I mentioned above the trickier part in using ADAL with my custom token cache was to ensure that I was using ADAL “the right way” in my app.  Arguably this really isn’t even specific to my custom token cache, it’s the way that I should be using ADAL anywhere, regardless of what caching mechanism is being used for it.  As I was describing before I’m using this with an ASP.NET app; that means that in order to get an access token I need to use the acquire token method in ADAL that uses an authorization code and client credential (so I can pass in the app secret).  What’s important in this process as well though (according to the Vittorio blog I referenced at the beginning) is that you use the user’s actual login Authority when you create the AuthenticationContext, versus just using common (i.e. https://login.windows.net/common/).   The last part of the flow is that when a user is ready to get an AuthenticationResult in subsequent requests, you should no longer ask for it using the authorization code – instead you should try one of the AcquireTokenSilent overloads.

So with all of this information in hand, here’s how the process works of getting an AuthenticationResult (which has the access token):

  • I have a table in Azure storage where I keep track of each user’s authentication parameters – UPN, resource ID, and login Authority.  When the user goes into a controller action that needs an access token I look in that table to see if I have a record matching the UPN and resource they are requesting.

  • The first time a user logs in, there won’t be any record so I redirect out to Azure to get an authorization code.

  • When Azure redirects to my controller, I see that there is an authorization code so I:
    • Create a new instance of AuthenticationContext, using my custom token cache:  authContext = new AuthenticationContext(“https://login.windows.net/common/&#8221;, new AdalAzureCache.TokenStore(upn));

    • Request an AuthenticationResult:  result = authContext.AcquireTokenByAuthorizationCode(AuthCode, new Uri(Request.Url.GetLeftPart(UriPartial.Path)), credential);

    • Store the user’s UPN, the ID of the resource they were requesting, and the login Authority in my custom storage for this app.  To be clear – this is storage just for this app – it is different from the storage that my custom token cache class uses.  The way I get the Authority for the user is after I’ve acquired an AuthenticationResult for them, the AuthenticationContext.Authority property has their specific Authority.

  • The next time the user needs an AuthenticationResult, I look in storage for my app and I find a record with the user’s UPN, resource and Authority.  In that case I:

    • Create a new instance of the AuthenticationContext; same as before but this time I use the user’s Authority:  authContext = new AuthenticationContext(“user’s authority here”, new AdalAzureCache.TokenStore(upn));

    • Request an AuthenticationResult silently:  result = authContext.AcquireTokenSilent(ResourceUri, credential, UserIdentifier.AnyUser);  This particular overload is one that I just found through trial and error to work with my token cache.

That’s basically it.  When the request to acquire the token silently is called, I see my custom token cache getting invoked.  It finds the token cache in Azure table storage for the user and resource and then sends it out for ADAL to use.  Everything just plugs in and out like a well-oiled machine and works. 

All of the source code for the OneDriveBrowser application that has been updated to use the new App Implementation described above and has been included, as well as the custom ADAL token cache that uses Azure table storage.  As with the previous OneDriveBrowser post, you will need to go into the Globals.cs in the AdalAzureCache and CloudHelper projects and plug in your Azure storage name and key (exception:  if you don’t want to compile it in AdalAzureCache you can pass the values in through the constructor as explained previously).  In the web.config file for the OneDriveBrowser MVC application you will need to go plug in your Azure application values. Hope you find it useful.

You can download the file here: