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.

7 thoughts on “Getting an Azure Access Token for a Web Application Entirely in Code

    • Yes, that is still the case. They have in fact gotten much worse – with ADAL 3.x they have removed support for one or more parts of the standards, so they are now LESS standards compliant than they were with the 2.x release. Specifically, they removed support for refresh tokens, not sure what all else may have been pulled as well. It’s a bad day for Microsoft and standards support, yet again.

      Like

  1. Have they removed support for the grant_type=password flow entirely? I get “The grant is not supported by this API version” when I try on the v2.0 API endpoint; and “Application [UUID] is not supported for this API version” on the v1 API endpoint.

    Even if I could get it to work, I wouldn’t be happy using an undocumented legacy API which could be withdrawn at any time.

    My application is for using Azure AD as a backend for wireless and VPN authentications. I want to take the username and password from a RADIUS request, send it to AAD to validate the password, and ideally use the “groups” or “roles” claims in the response to authorize the user. Microsoft is making this apparently very simple thing very hard indeed.

    It might be possible to do something using a VM in the Azure Cloud – maybe a VM could talk to Azure AD as if it were a domain controller, and validate passwords by getting a Kerberos ticket? But I don’t want to build things in Azure Cloud because it would be a whole new set of VPN tunnels to set up.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s