asp.net-web-apimulti-tenantopenid-connectazure-ad-b2cowin-middleware

Sharing single WebApp and API deployment with multiple B2C Tenants


Current scenario: Web App and Web API are authenticated using AAD B2C and working fine. Each customer has a unique tenant. OpenIdConnectAuthenticationOptions (web app) and OAuthBearerAuthenticationOptions (api) are set at the application Startup.

As described here: Token based authentication for both Web App and Web API using Azure AD B2C

Unfortunately both Web app and API have to be deployed for each and every customer to keep them separated.

Requirement: Use same Web app and API for multiple customers rather than deploying them for every customer. Each customer will have a different URL for the web application.

enter image description here

Question 1 (Web App): How to redirect (for authentication) users to the correct tenant based on the request URL?

i.e. Set OpenIdConnectAuthenticationOptions (tenant, applicationId, signInPolicy etc.) from the database (or memory) on the fly based on the Request.Url rather than at application Startup.

Question 2 (API): How to validate the received token using the correct tenant?

i.e. Set OAuthBearerAuthenticationOptions configurations on the fly based on the received token clientId rather than at the application Startup


Solution

  • Per @ManishJoisar's request this is how I resolved my issue long ago. This is an old .net framework 4.8 code sample.

    Please note that B2C v2 policies provide better implementation with federation through custom policies these days.

    public void ConfigureAuth(IAppBuilder app)
        {
    
            int index = 2000;
            foreach (var record in SystemConfig.ApiToWebUrl)
            {
                app.MapWhen(
                        context => System.Web.HttpContext.Current.Request.Url.BaseURL() == record.Key,
                        config =>
                        {
                            var customer = SystemConfig.GetWebSettings(true)[record.Value];
                            config.UseOAuthBearerAuthentication(CreateBearerOptionsFromPolicy(index, customer.B2CSignInPolicyId,
                                                    customer.B2CAadInstance, customer.B2CTenant, customer.B2CApplicationId));
                        }
                    );
    
                index++;
            }
        }
    
        public OAuthBearerAuthenticationOptions CreateBearerOptionsFromPolicy(int index, string b2cPlicyName,
                        string b2cInstance, string b2cTenant, string b2cClientId)
        {
            TokenValidationParameters tvps = new TokenValidationParameters
            {
                // This is where you specify that your API only accepts tokens from its own clients
                ValidAudience = b2cClientId,
                AuthenticationType = string.Format("{0}_{1}", b2cPlicyName, index)
            };
    
            var aadInstance = string.Format("https://{0}{1}", b2cTenant.Split('.')[0], ".b2clogin.com/{0}/{1}/v2.0/.well-known/openid-configuration");
    
            var config = String.Format(aadInstance, b2cTenant, b2cPlicyName);
    
            return new OAuthBearerAuthenticationOptions
            {
                // This SecurityTokenProvider fetches the Azure AD B2C metadata & signing keys from the OpenIDConnect metadata endpoint
                AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider(config)),
                Provider = new CustomOAuthBearerProvider()
            };
        }