Integrate Azure AD B2C with ASP.NET MVC Web Application

Introduction

Azure B2C is a business-to-customer identity management as service. Using Azure AD B2C service, customers can use their social, and local account identities to get SSO (Single sign-on) access to their applications and APIs. In this article, you will learn how to integrate Azure B2C Service with our ASP.NET MVC Web application.
This is a series of my Azure AD B2C articles. I strongly recommend you go through my previous articles on Azure AD B2C.

Create a MVC Web Application

Create a new ASP.NET Web application using Visual Studio and name the application. In my case, I named it “AzureADB2C.MVCWebClient”.

.NET Framework MVC application

Select the MVC template and create a project with No authentication.

MVC Template

Make sure the “configure for HTTPS” option is checked.

Install the needed NuGet Packages to Configure the MVC App

Open the NuGet Package Manager Console and install the below packages:

Install-Package Microsoft.Owin.Security.OpenIdConnect -Version 3.0.1

Install-Package Microsoft.Owin.Security.Cookies -Version 3.0.1

Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.1

Update-package Microsoft.IdentityModel.Protocol.Extensions

The “Microsoft.Owin.Security.OpenIdConnect” package comprises middleware essential for securing web applications through OpenID Connect. This package handles the intricate process of communication between our MVC application and the Azure B2C tenant. It manages tasks such as token request and validation, simplifying the integration of OpenID Connect authentication in our web application.        

The “Microsoft.IdentityModel.Protocol.Extensions” package includes classes that define constants and messages for OpenID Connect. Additionally, the “Microsoft.Owin.Security.Cookies” package is utilized to establish a session based on cookies after obtaining a valid token from our Azure AD B2C tenant. This cookie, sent from the browser to the server with every subsequent request, is validated by the cookie middleware.

Register a new application in Azure B2C

Step 1: Log in to Azure portal and switch to Azure B2C tenant.

Step 2: Click on App registrations and create a new registration.

App new registration

 I named it WebAppDemo, Redirect URI – https://localhost:44383/signin-iodc, grant admin consent, and click on Register.

After application registration, hop to authentication from Manage Blade and check

   Click on save to save the changes.

Configure Web App to use Azure AD B2C tenant IDs and Policies

Now we need to modify the web. config for our MVC App by adding the below keys, so open Web. config and add the below AppSettings keys:

   <add key="ida:ClientId" value="afec67b9-2c58-4a50-a6d9-14789e9b5fb0" />
	  <add key="ida:AadInstance" value="https://gowthamcbe.b2clogin.com/gowthamcbe.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1A_SIGNUP_SIGNIN" />  
	  <add key="ida:SignUpSignInPolicyId" value="B2C_1A_SIGNUP_SIGNIN" />
	  <add key="ida:RedirectUri" value="https://localhost:44383/signin-oidc" />

The tenant name is the domain name as shown in the below figure.

Client ID is the application client id, go to the newly created application and copy the client id.

Create an OWIN start-up class, right-click on App_Start, and select the Owin startup class as shown below figure.

Add the below code to the Startup.cs

using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Notifications;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.Owin.Security;
using Owin;
using System;
using System.Threading.Tasks;
using System.Configuration;

[assembly: OwinStartup(typeof(AzureADB2C.MVCWebClient.App_Start.Startup))]

namespace AzureADB2C.MVCWebClient.App_Start
{
    public class Startup
    {
        private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
        private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
        private static string tenantId = ConfigurationManager.AppSettings["ida:Tenant"];
        private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
        public static string  signUpSignInPolicyID = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
     
        public void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(signUpSignInPolicyID));
        }
      
        private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
        {
            return new OpenIdConnectAuthenticationOptions
            {
                // For each policy, give OWIN the policy-specific metadata address, and
                // set the authentication type to the id of the policy
                MetadataAddress = String.Format(aadInstance, tenantId, policy),
                AuthenticationType = policy,

                // These are standard OpenID Connect parameters, with values pulled from web.config
                ClientId = clientId,
                RedirectUri = redirectUri,
                PostLogoutRedirectUri = redirectUri,

                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthenticationFailed = AuthenticationFailed
                },
                Scope = "openid",
                ResponseType = "id_token",

                // This piece is optional - it is used for displaying the user's name in the navigation bar.
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "emails",
                    SaveSigninToken = true //important to save the token in boostrapcontext
                },
            };
        }

    private Task AuthenticationFailed(AuthenticationFailedNotification<Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
        {
            notification.HandleResponse();
            notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
            return Task.FromResult(0);
        }
    }
}

Add the owin startup in web.config file

<add key="owin:AutomaticAppStartup" value="true"/>

Call the Azure B2C Polices

Now we need to configure our Web App to invoke the policies we created, to do so we need to add a new controller named “AccountController”, so add it and paste the code below:

public class AccountController : Controller
    {
        public void SignIn()
        {
           if (!Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Set("Policy", Startup.signUpSignInPolicyID);
                HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" },
                    Startup.signUpSignInPolicyID);
            }
        }
 
        public void SignUp()
        {
            if (!Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.Challenge(
                    new AuthenticationProperties() { RedirectUri = "/" }, Startup.SignUpPolicyId);
            }
        }
 
        public void Profile()
        {
            if (Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.Challenge(
                    new AuthenticationProperties() { RedirectUri = "/" }, Startup.ProfilePolicyId);
            }
        }
 
        public void SignOut()
        {
            // To sign out the user, you should issue an OpenIDConnect sign out request
            if (Request.IsAuthenticated)
            {
                IEnumerable<AuthenticationDescription> authTypes = HttpContext.GetOwinContext().Authentication.GetAuthenticationTypes();
                HttpContext.GetOwinContext().Authentication.SignOut(authTypes.Select(t => t.AuthenticationType).ToArray());
            }
        }
    }

What we have implemented here is simple, and it is the same for actions SignIn ,  SignUp , and  Profile , what we have done is a call to the  Challenge method and specify the related Policy name for each action.

In the OWIN pipeline, the “Challenge” method takes an instance of the AuthenticationProperties() object, allowing us to configure actions such as signing in, signing up, or editing a profile. Specifically, we set the “RedirectUri” within this method to the root path of our web application. It’s important to note that this “RedirectUri” is unrelated to the one defined in Azure AD B2C. This separate “RedirectUri” determines where the user’s browser redirects them after a successful operation, providing flexibility in handling post-operation navigation.

When dealing with the SignOut action, it’s necessary to log out the user from multiple sources. Firstly, this involves terminating the local session created by the “Cookies” authentication in our app. Additionally, it requires notifying the OpenID Connect middleware to dispatch a SignOut request to our Azure AD B2C tenant, ensuring the user is also signed out from there. To achieve this, we retrieve all available authentication types associated with our web application. Subsequently, these diverse authentication types are passed as parameters to the “SignOut” method, facilitating the comprehensive logout process.

Next, include a partial view that displays links to invoke these actions. Create a new partial view called “_LoginPartial.cshtml” within the “Shared” folder, and copy and paste the provided code into it.

@if (Request.IsAuthenticated)
{
    <text>
        <ul class="nav navbar-nav navbar-right">
            <li>
                <a id="profile-link">@User.Identity.Name</a>
                <div id="profile-options" class="nav navbar-nav navbar-right">
                    <ul class="profile-links">
                        <li class="profile-link">
                            @Html.ActionLink("Edit Profile", "Profile", "Account")
                        </li>
                    </ul>
                </div>
            </li>
            <li>
                @Html.ActionLink("Sign out", "SignOut", "Account")
            </li>
        </ul>
    </text>
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li>@Html.ActionLink("Sign up", "SignUp", "Account", routeValues: null, htmlAttributes: new { id = "signUpLink" })</li>
        <li>@Html.ActionLink("Sign in", "SignIn", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
    </ul>
}

Notice that part of the partial view will be rendered only if the user is authenticated and notice how we are displaying the user “Display Name” from the claim named “name” by only calling  @User.Identity.Name

Now we need to reference this partial view in the “_Layout.cshtml” view, we need just to replace the last Div in the body section with the below section:

<div>
<li>@Html.ActionLink("Home", "Index", "Home")</li>
		<li>@Html.ActionLink("Orders List", "Index", "Orders")</li>
	</ul>
	@Html.Partial("_LoginPartial")
</div>

Run the application and test the login

Click on Sign in, the Azure AD B2C login screen will appear.

Sign In flow

Summary:

We have seen how to register the application in Azure AD B2C to integrate it with ASP.NET MVC Web application and we successfully configured the SignIn and Sign Up flow which was created in my previous article. Will see more about other flow integration in my next articles.

Download source code

gowthamk91

Leave a Reply

%d