I am using Azure AD B2C to authenticate in an AspNetCore RC2 MVC application, this partially works in that when I navigate to an action that requires authentication I am redirected to the B2C login page accordingly. When I successfully login I am correctly redirected to my application page (and I can see the id_token field appropriately provided in the query parameters). Unfortunately the pipeline authentication middleware does not seem to correctly processing the redirect query parameters as it immediately redirects me to the login page. Can anyone advise?
The code I am using is below:
public static void UseOAuth(this IApplicationBuilder app)
{
// By default, all middleware are passive/not automatic. Making cookie middleware automatic so that it acts on all the messages.
app.UseCookieAuthentication( new CookieAuthenticationOptions{ AutomaticAuthenticate = true, CookieSecure = CookieSecureOption.Never });
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions {
ClientId = B2CAuthentication.ClientId,
ResponseType = OpenIdConnectResponseTypes.IdToken,
Authority = string.Format(CultureInfo.InvariantCulture, B2CAuthentication.AadInstance, B2CAuthentication.PortalTenant, string.Empty, string.Empty),
AuthenticationScheme = "Cookies",
Events = new OpenIdConnectEvents
{
OnAuthenticationFailed = OnAuthenticationFailed,
OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
OnAuthorizationCodeReceived = OnAuthorizationCodeReceived,
OnTokenResponseReceived = OnTokenResponseReceived,
OnTokenValidated = OnTokenValidated,
OnTicketReceived = OnTicketReceived,
OnMessageReceived = OnMessageReceived,
OnRedirectToIdentityProviderForSignOut = OnRedirectToIdentityProviderForSignOut,
OnRemoteFailure = OnRemoteFailure,
OnUserInformationReceived = OnUserInformationReceived
},
// The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
// endpoints from the OpenID Connect metadata endpoint. It is included in the PolicyAuthHelpers folder.
ConfigurationManager = new PolicyConfigurationManager(
string.Format(CultureInfo.InvariantCulture, B2CAuthentication.AadInstance, B2CAuthentication.PortalTenant, "/v2.0", "/" + OpenIdProviderMetadataNames.Discovery),
new string[] { B2CAuthentication.ResetPolicy, B2CAuthentication.CommonPolicy, B2CAuthentication.SignInPolicy })
});
}
private static Task OnUserInformationReceived(UserInformationReceivedContext arg)
{
...Never called...
}
private static Task OnRemoteFailure(FailureContext arg)
{
...Never called...
}
private static Task OnRedirectToIdentityProviderForSignOut(RedirectContext arg)
{
...Never called...
}
private static Task OnMessageReceived(MessageReceivedContext arg)
{
...Never called...
}
private static Task OnTicketReceived(TicketReceivedContext arg)
{
...Never called...
}
private static Task OnTokenValidated(TokenValidatedContext arg)
{
...Never called...
}
private static Task OnTokenResponseReceived(TokenResponseReceivedContext arg)
{
...Never called...
}
private static Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext arg)
{
...Never called...
}
private static async Task OnRedirectToIdentityProvider(RedirectContext context)
{
PolicyConfigurationManager mgr = (PolicyConfigurationManager)context.Options.ConfigurationManager;
if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
OpenIdConnectConfiguration config = await mgr.GetConfigurationByPolicyAsync(CancellationToken.None, B2CAuthentication.CommonPolicy);
context.ProtocolMessage.IssuerAddress = config.EndSessionEndpoint;
}
else
{
OpenIdConnectConfiguration config = await mgr.GetConfigurationByPolicyAsync(CancellationToken.None, B2CAuthentication.CommonPolicy);
context.ProtocolMessage.IssuerAddress = config.AuthorizationEndpoint;
context.ProtocolMessage.RedirectUri = "http://localhost:8080/Portal/";
context.ProtocolMessage.ResponseType = OpenIdConnectResponseTypes.IdToken;
context.ProtocolMessage.ResponseMode = OpenIdConnectResponseModes.Query;
}
}
private static Task OnAuthenticationFailed(AuthenticationFailedContext context)
{
context.HandleResponse();
context.Response.Redirect("/Home/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
I've managed to get this to work by doing the following:
Fundamentally I think the use of the CallbackPath, the change to AuthenticationScheme and the change of ResponseMode to FormPost all contributed to the fix.
public static void UseOAuth(this IApplicationBuilder app)
{
// By default, all middleware are passive/not automatic. Making cookie middleware automatic so that it acts on all the messages.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
CookieName = "MyCookieName",
CookieSecure = CookieSecureOption.Never,
AuthenticationScheme = "Cookies"
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions {
AutomaticAuthenticate = true,
Authority = string.Format(CultureInfo.InvariantCulture, B2CAuthentication.AadInstance, B2CAuthentication.PortalTenant, string.Empty, string.Empty),
ClientId = B2CAuthentication.ClientId,
ResponseType = OpenIdConnectResponseTypes.IdToken,
AuthenticationScheme = "oidc",
ResponseMode = OpenIdConnectResponseModes.FormPost,
CallbackPath = "/",
Scope = { "openid" },
Events = new OpenIdConnectEvents
{
OnAuthenticationFailed = OnAuthenticationFailed,
OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
OnTokenValidated = OnTokenValidated,
OnRemoteFailure = OnRemoteFailure
},
// The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
// endpoints from the OpenID Connect metadata endpoint. It is included in the PolicyAuthHelpers folder.
ConfigurationManager = new PolicyConfigurationManager(
string.Format(CultureInfo.InvariantCulture, B2CAuthentication.AadInstance, B2CAuthentication.PortalTenant, "/v2.0", "/" + OpenIdProviderMetadataNames.Discovery),
new string[] { B2CAuthentication.ResetPolicy, B2CAuthentication.CommonPolicy, B2CAuthentication.SignInPolicy })
});
}
Using
ResponseType = OpenIdConnectResponseType.Code
inside
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
...
});
seems to make the middleware prompt for the CodeReceived event.
Also add Microsoft.AspNetCore.Mvc.Formatters.Xml
to project.json to get away from the Could not load file or assembly System.Private.DataContractSerialization
error
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With