Getting an Azure Access Token for a Web Application Entirely in Code
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.