Yesterday I talked about a bug which prevented me to complete the authorization grant flow with Azure AD. It turn out the bug is only exposed when using Azure Management Portal for Relying party registration. In this post, I’ll use Graph Explorer to do the registration which works fine.

My scenario is to create a simple MVC application which would do the user authentication against the Azure AD.

Once the user is signed in, the web app then acquires an “access” & “refresh token” for the Graph API (I’ll work with other resources in future) using the 3-leg authorization grant flow.

I started by creating an empty MVC 4.0 application and added a home controller with a simple view displaying the identity & claims of the authenticated user.

image

Running the app gave me the url which I would use to register my app with Azure AD using Graph Explorer.  Registration instruction are available in this blog post under the ‘Setting up permissions’ section. My registration settings looks like this

image

Now back to VS and using the “Identity & Access”, I have externalized the authentication of my app to windows azure AD.

image

The tooling does all the magic and generates required WIF configuration.

<system.identityModel>
<identityConfiguration>
<audienceUris>
<addvalue="http://localhost:45906/" />
</audienceUris>
<issuerNameRegistrytype="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<trustedIssuers>
<addthumbprint="3464C5BDD2BE7F2B6112E2F08E9C0024E33D9FE0"name="https://sts.windows.net/{tenantid}/" />
</trustedIssuers>
</issuerNameRegistry>
<certificateValidationcertificateValidationMode="None"/>
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandlerrequireSsl="false" />
<wsFederationpassiveRedirectEnabled="true"issuer="https://login.windows.net/common/wsfed"realm="http://localhost:45906/"reply="http://localhost:45906/"requireHttps="false" />
</federationConfiguration>
</system.identityModel.services>

Now when I run my application, I’m redirected to azure AD for authentication and after signing in, I’m back in my app with following claims.

image

The Authorize action simply redirects to the authorization endpoint requesting an ‘authorization code’.

Acquire authorization code
publicActionResult Authorize()
{
var @params = newNameValueCollection
{
{"response_type", "code"},
{"client_id", "87638e3d-6b56-46b6-946f-8b3b9fa6f04e"},
{"resource", "https://graph.windows.net"},
{"redirect_uri", Url.Action("Authorized", null, null, "http")}
};
var query = HttpUtility.ParseQueryString("");
query.Add(@params);    return Redirect(Constants.AzureADAuthorizationEndpoint + "?" + query);
}

 

I’m passing Authorized action as the redirect_uri to Azure AD. That’s where AD would send me the ‘authorization code'.

Clicking the ‘Authorize’ link takes me to Azure Ad & after authentication AD redirects my browser back to Authorized action with an authorization code.

http://localhost:45906/Home/Authorized?code=AAAAAAAAcJ3MFRmxlJAB5CwTBrXmI7t8zdfTrUmfPCbGHQCxbWXOxLieUD4r_fah-rnOwQkxS6B_KOSdLhjsf6n5sQghMwu9ynqFD2-qHBfRkxE3DnS8htlHaDqCdG-Wa5MvbRXZeCKUFr-k37n5Mn4T2KCdKx-nkyNheqZJmwmDFWwix_Gi_QJohhUMk-SDyrnV4Jy-tT_gfiKwKRzVi31JmsJV_b8u-5p398GsGfxBlfxuWuNYuUiUOUDdfLQCYbK0urn0HChsndnPuTZJxtJtNH7WdWnUdha108kVctvHW4u8IihV9P10OsM1gT_D67f00SjVIAA

From the Authorized controller action I fire a post request which gives me access and refresh tokens back. Please note, the redirect_uri MUST be same for both authorization code and token request.

Exchange code with tokens
publicasyncTask<ActionResult> Authorized(string code)
{
if (string.IsNullOrEmpty(code))
RedirectToAction("Index");    var data = newDictionary<string, string>
{
{"grant_type", "authorization_code"},
{"client_id", "87638e3d-6b56-46b6-946f-8b3b9fa6f04e"},
{"redirect_uri", Url.Action("Authorized", null, null, "http")},
{"client_secret", "V/7FTVm****************UQi6MkbwhmBqKxz0="},
{"code", code}
};

var client = newHttpClient(newWebRequestHandler());
var response = await client.PostAsync(Constants.AzureADTokenEndpoint, newFormUrlEncodedContent(data));
response.EnsureSuccessStatusCode();

var msg = await response.Content.ReadAsStringAsync();
var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(msg);
return View(tokenResponse);
}

image

The access & refresh tokens are scoped to Graph API in this case. I can now attach this “access token” to my requests to graph API to read/write the directory data. There are few samples on this topic already so I’m not going to cover that in this post.

Source: HomeController.cs