Azure AD part 4 – minimal approach to authentication

Following up on my previous blog posts on Azure AD, I got the idea in my head to see what the minimal approach would be to implement Azure AD authentication in a DotNet based web application. Yes, there are componants you should use, like OWIN, ADAL, MSAL, etc, but how do they really work and just how big task is it to implement yourself if you really wanted – that was the question I wanted to answer.

The simple web application

I created an empty WebForms application with just a Default.aspx page. I deliberately choose WebForms since all modern examples of AAD auth are MVC/OWIN based. In the end I just added the Global.asax page, a page called Login.aspx and a C# class with just a few static methods and I was able to integrate with azure AD for authentication.

aaddotnet-website-1When the user press the “Azure AD Login” menu item, it goes to the Login page with action=login.

Azure AD authentication via OAuth and OpenID

There are numerous flow charts out on the internet explaining the interaction between the browser, your web application and the Identity Provider (IDP) and to be honest, it can look a bit complex. Azure AD supports OAuth and OpenID and in Microsofts documentation of OpenID and important detail about OpenID is explained

“OpenID Connect 1.0 in Azure Active Directory (Azure AD) enables you to use the OAuth 2.0 protocol for single sign-on. OAuth 2.0 is an authorization protocol, but OpenID Connect extends OAuth 2.0 for use as an authentication protocol. A primary feature of the OpenID Connect protocol is that it returns an id_token, which is used to authenticate the user.” (see refs)

So, by redirecting from my web application to Azure AD, asking for an OAuth authorization AND asking for a response_type=id_token, we can do a authorization/authentication in one call.

Login Sequence

By using Fiddler, we can get a clear understanding of what is happening here. Clicking on the menu item in the browser calls the Login.aspx page (frame 31) which responds with a redirection url to Azure AD. The browser redirects to Azure AD in frame 33 asking for an authentication. In the query parameter, we pass identification of the web application (redirect_uri, clientID and clientSecret) which are items we have registered in Azure AD.

aaddotnet-fiddler-1

The important part is responseType=id_token, which tells Azure AD to return a JWT Token on a successfull authentication. Azure AD responds with yet a redirection request to the browser and this time to the destination we supplied in the callbackURL parameter. You can see the browser making this call in frame 35.

aaddotnet-fiddler-2

Code that handles clicking on the login link and that returns the redirection url to Azure AD

We’re authenticated, now what?

The callback to Login.aspx then has to decode the JWT token and covert them to claims and setting up a claims identity. But that is not all. In order keep this on a session level we need to create a cookie on the callback processing and for each subsequent request, we need to read this cookie and recreate/reapply the claims identity. Simple, right?

Step 1 – Handling the Callback

First, we shouldn’t do anything if we are already authenticated or ir the callback is missing the id_token in it’s post body. Second, decode the JWT token into JSON and create a ClaimsPrincipal. Third, create the FormsAuthenticationTicket where we store the JWT token in the UserData section so that we always have it available. Fourth, create the cookie using the well known name ASPXAUTH (FormsCookieName) and redirect ourselves to wherever we should go after authentication is complete

Creating the ClaimsPrincipal is straight forward. Setting the HttpContext.Current.User makes the boolean flag Request.IsAuthentication flip from false to true, which is important since that is how we check in code if we are dealing with an anonymous or authenticated user. Setting Thread.CurrentPrincipal makes the claims available since the static method ClaimsPrincipal.Current actually uses this value.

 

aaddotnet-cookie-1

Step 2 – Reapplying the cookie on each subsequent Request

If we do nothing on the following request, the flag Request.IsAuthenticated will be false, so we need to recreate the ClaimsPrincipal and reapply on each subsequent request. This is the only way it can work if your web applicaiton is hosted on multiple servers.

In Global.asax there is a method that is there just for this and it’s called AuthenticateRequest

 

The end result is a web page that behaves just like you expect and that can show the claim values we created.

aaddotnet-website-3

Logoff

Logging off is basically the same process but simpler. It’s a redirect to Azure AD again asking it to logoff and at the same time making sure the cookie we have is set to expired.

Summary

This excersie is about showing you that you can roll your own implementation of integrating Azure AD authentication in your web application. In doing so I hope I gave you an understanding of how easy it is and how it really works behind the covers. However, with Identity you should NEVER roll your own solutions and should ALWAYS use componants that are tested and maintained by bigger players.

References

OpenID 1.0 Connect
https://msdn.microsoft.com/en-us/library/azure/dn645541.aspx

OpenID 1.0 Specifications
http://openid.net/developers/specs/

Authorize webapps with OAuth and Azure AD
https://azure.microsoft.com/en-us/documentation/articles/active-directory-protocols-oauth-code/

Azure AD Developer’s Guide
https://azure.microsoft.com/en-us/documentation/articles/active-directory-developers-guide/

Sources

Available on github
https://github.com/cljung/azwebaadtiny