I have a scenario where I want to authenticate two distinct user types on my system: "Clients" are external to the organization, and will be using the Azure AD B2C user/password flow or one of the social identity providers, "Agents" are members of an organization that uses corporate authentication (AD for now, but likely to be another provider down the line). I do not want them hitting the same login page as that would lead to confusion (so agents will never see the user/password or social logins, clients will never see the corporate login.
So what I've been working on is having two AD B2C flows, similar to the process described here: https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant, except rather than having them both be enabled on a single app registration on the B2C tenant I have two separate App Registrations. Each of these registrations is set up to have its own Web Redirect URI (https://localhost:/openid/azure_ad_b2c_client and https://localhost:/openid/azure_ad_b2c_agent).
My service configuration looks like this:
var section = configuration.GetSection(ConfigSection);
var authenticationScheme = section.GetValue("AuthenticationScheme", DefaultAuthenticationScheme);
var cookieScheme = section.GetValue("CookieScheme", DefaultCookieScheme);
services
.AddAuthentication(authenticationScheme)
.AddMicrosoftIdentityWebApp(
(MicrosoftIdentityOptions options) =>
{
configuration.Bind(ConfigSection, options);
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = false;
options.Events.OnTicketReceived = OnTicketReceived;
options.Events.OnRedirectToIdentityProvider = OnRedirectToIdentityProvider;
options.Events.OnRemoteFailure = OnRemoteFailure;
},
configureCookieAuthenticationOptions: null,
openIdConnectScheme: authenticationScheme,
cookieScheme: cookieScheme,
subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: false);
I have specified different cookie schemes, authentication schemes, and callback paths for each of these service configurations in appsettings sections:
"AzureAdB2CClient": {
"Instance": "https://<mydomain>.b2clogin.com/tfp/",
"ClientId": "<appregistration1_clientId>",
"CallbackPath": "/openid/azure_ad_b2c_client",
"Domain": "<mydomain>.onmicrosoft.com",
"SignUpSignInPolicyId": "B2C_1_Dev_SUSI_Client",
"ResetPasswordPolicyId": "",
"EditProfilePolicyId": "",
"Tenant": "<adb2ctenantid>",
"CookieScheme": "ClientCookie",
"AuthenticationScheme": "AzureAdB2CClient"
},
"AzureAdB2CAgent": {
"Instance": "https://mydomain.b2clogin.com/tfp/",
"ClientId": "<appregistration2_clientId>",
"CallbackPath": "/openid/azure_ad_b2c_agent",
"Domain": "mydomain.onmicrosoft.com",
"SignUpSignInPolicyId": "B2C_1_Dev_SUSI_Agent",
"ResetPasswordPolicyId": "",
"EditProfilePolicyId": "",
"Tenant": "<adb2ctenantid>",
"CookieScheme": "AgentCookie",
"AuthenticationScheme": "AzureAdB2CAgent"
},
Each of these setups works individually, but if I configure them together I run into two issues:
- Regardless of which challenge I issue (
await HttpContext.ChallengeAsync(authenticationScheme, authenticationProperties);
the last one configured is always run
- After running through the login flow (either one) authentication fails with an
Unable to unprotect the message.State.
message on the RemoteFailureContext in my OnRemoteFailure delegate. Discussion I've found around this message suggests there is a conflict on the CallbackPath which I suppose might be because these two services are somehow overwriting one another (with only the last configured one seeming to work).
So from this, I have the following questions:
- Is it even possible to run multiple B2C configurations like this, or am I taking the wrong approach? i.e. is there a simpler way to do this than messing with two separate app registrations?
- Is there perhaps something I'm missing that needs to be unique between the configurations other than the auth scheme, cookie scheme, and callback?
Thanks :)
question from:
https://stackoverflow.com/questions/65885004/using-multiple-azure-ad-b2c-app-registrations-conflict-and-remote-failure-with