Authenticating an ASP.NET Core web app using Azure AD - Part 2

Overview

I my previous post I showed how to create a ASP.NET Core MVC web app in Visual Studio 2017 and authenticate an user with Azure Active Directory (AAD). It is high time I get to the seond part to show what happens under the covers. For this I will be using Fiddler for capturing the HTTP traffic as I load the web app on a browser and authenticate my user.

Authentication Flow

I captured the HTTP traffic using Fiddler. This is how the trace looks.
Fiddler SignIn Trace

So what's going on here. If I draw this as a sequence diagram it will be more clear.
SignIn Sequence Diagram Let me describe each sequence of the flow in details

Step 1

This is simple. I click the sign in button and the code in SignIn action of the Account controller is executed. As I am not authenticated the OpenIdConnectAuthentication middleware returns a 302 response and the browser redirects to Azure AD login endpoint. The trace details are shown below.

Request:
Step 1 Request Response:
Step 1 Response Note the URL in Location.
The browser redirects to https://login.microsoftonline.com/98f32fa0-d913-4806-9aae-f8a3851849ed/oauth2/authorize

Step 2

In this step the browser sends GET request to the redirect_uri from step 1 and the login form is displayed.

The query parameters are
Step 2 Request

  • client_id: This identifies the application to Azure AD
  • redirect_uri: This is the URL to which the browser should redirect once the authentication is successful
  • response_type: id token; i.e. A access token should be returned.
  • scope: openid profile
  • response_mode: form post
  • nonce: A random value to prevent replay attack
  • state: Some state information.

In response the Sign In page is shown with the form fields to enter the login (userid) and the password.
Step 2 Response This is where I enter testuser@ADSample101.onmicrosoft.com

Step 3

At this point a AJAX call is made as can be seen in the header X-Requested-With: XMLHttpRequest. This is call only to check if this email is associated with multiple accounts. It is not important in the context of this authentication flow. In this case nothing changes.
Step 3 Request Step 3 Response

Step 4

This is an important step. Here the browser posts the form with the login and password to the login endpoint of Azure AD https://login.microsoftonline.com/98f32fa0-d913-4806-9aae-f8a3851849ed/login.
Step 4 Request The response has a hidden form with the access token.

<html>  
<body>  
    <form method="POST" name="hiddenform" action="http://localhost:37873/signin-oidc">
        <input type="hidden" name="id_token" value="JWT" />
    ... 
    </form>
    <script language="javascript">document.forms[0].submit();</script>
</body>  
</html>  

This form has a form field named idtoken containing the token in the JWT format (I have removed the actual value) and the POST URL is the same as the redirecturi passed in step 2. In other words the id_token is passed to the browser. This is subsequently posted to our web app by JavaScropt as shown above.

Let's check the claims within the JWT token using the decoder at JWT.io. You can read details about JWT from this website. Basically it is a BASE64 encoded 3 parts JSON separated by a '.' and cryptographically signed by the issuer.
JWT Token Decoded The token contains the claims which are just key:value attributes about my user returned by the issuer, in this case Azure AD. Some of the interesting claims are

  • aud: This is the audience, which is the same value as the application_id we got from Azure AD
  • iss: This is the issuer
  • iat: Issued At. The time the token was issued in UNIX epoch time format.
  • nbf: Not Before. The token is not valid before this time.
  • exp: Expiry. The time when the token expires.
  • family name, given name, name: Pretty obvious.
  • upn: User Principal Name. The login id of the user.

Step 5

The form from step 4 is posted to our web app OpenID Connect endpoint http://localhost:63599/signin-oidc by a bit of JavaScript.
The OpenID Connect authentication middleware handles this and authenticates the user.
Step 5 Request

The response code is 302 which is a redirect to the url '/' , i.e. the home page as configured in the code in SignIn action. The response also saves cookies which will be used to authenticate the user in subsequent requests.
Step 5 Response Cookies

Step 6

Finally the browser redirects to the homepage and the user is authenticated. The claims in the token as use to create a ClaimsIdentity and the About controller loops over the claims and displays them.
About page

Signout Flow

Let's also do a sign out and see what happens. The Fiddler trace is
Fiddler SignOut Trace

The sequence diagram is below.
SignOut Sequence Diagram

Step 7

Clicking the SignOut link causes the browser to do a GET request on http://localhost:63599/Account/SignOut. This is handled by the SignOut action in Account controller. The code signs out both the authentication middleware. A 302 response is send to the browser and it is redirected to the Azure AD sign out endpoint.
The cookies are also cleared in the response.
Step 7 Response Cookies

Step 8

The browser redirects to the logout endpoint in Azure AD passing the post logout redirect uri (as set in appsettings.json) as a query parameter.
Step 8 Request

In response a logout HTML page from Azure page is returned. This has some JavaScript code to redirect the browser to the redirect uri after a small time period.

function InitiatorRedirect()  
{
    window.location = "http://localhost:63599/signout-callback-oidc?state=";
}

Step 9

The browser is now redirected to the signout URL http://localhost:63599/signout-callback-oidc.
This returns a 302 response with Location header value set to http://localhost:63599/

Step 10

The browser is now redirected to the home page "/" and the user is unauthenticated.

Summary

I have shown and explained what is going on under the hood for this authentication scenario. This is a redirection based flow. I hope this makes it clear.

Pratik Khasnabis

Solution architect, Azure expert, API designer, C# programmer, Data Science learner, IT geek and Star Wars fan. MCSD Azure Solution Architect, MCSD Web Applications and TOGAF certified.

Melbourne