5

I am trying to get a ASP.NET Core 2.1 web app running with Azure AD B2C. I have this running after much reseach (and more trial and error) as the instructions found in the docs are a little off.

The sign-in/sign-up process works using the default scaffolding during the project setup wizard, plus the new Microsoft.AspNetCore.Authentication.AzureADB2C.UI Nuget, which resulted in a simplified, yet "back boxed" experience during startup.

The problem currently is that I am unable to make this work with a custom Reply URL that is different from "signin-oidc". I have read that "signin-oidc" is baked into the provider somehow, and is hence the default.

I have a OnboardingController with a Start action defined where I want the user to land after signing up, so I have done the following:

  • A) I tested that the Url localhost:12345/Onboarding/Start works. The page is displayed correctly.
  • B) In appsettings.json I change AzureAdB2C's "CallbackPath": "/signin-oidc" to "CallbackPath": "/Onboarding/Start" appsettings
  • C) I go to the tenant and change the application's Reply URL to localhost:12345/Onboarding/Start. IMPORTANT side note: Unlike in the ADB2C samples and guides, you MUST append the Reply URL with either signon-oidc or a custom request path! Localhost:12345 is NOT ENOUGH! tenant config

    I can confirm the authentication worked: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: AzureADB2CCookie signed in. Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 56.201ms

Then, when I manually navigate to /Onboarding/Start in the browser, I get

Error from RemoteAuthentication: Correlation failed.

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:12345/Onboarding/start  
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Warning: .AspNetCore.Correlation. state property not found.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: Error from RemoteAuthentication: Correlation failed..

1. But I am never redirected to the intendend /Start page. instead I land back on the root homepage, just like what happens when I used 'signin-oidc'. Why is that and how do I make it stop going there?

2. How can I have the Reply URL be different depending on whether you sign IN or UP? I can't really use a sign-up policy for one and a separate sign-in policy for the other, because the reply URL is identical.

I am new to .Net Core and I am at a loss as to how to even debug this. Signing in with B2C seems to be an obscure process. Any insight would be greatly appreciated.

EDIT: This is the custom account controller, which is not built into the Nuget package for AzureADB2C. While the Nuget package provides an internal AccountController, it does not allow you to set a custom Reply URL. Yet using my own account controller does not work for me. I am also not getting the "Correlation failed" error either, instead I get no error at all.

[Route( "[controller]/[action]" )]
    public class AccountController : Controller
    {
        private readonly AzureADB2COptions azureAdB2COptions;
        private const string PolicyAuthenticationProperty = "Policy";
        private string scheme = AzureADB2CDefaults.AuthenticationScheme;

        public AccountController( IOptions<AzureADB2COptions> b2cOptions )
        {
            azureAdB2COptions = b2cOptions.Value;
        }

        [HttpGet]
        [Route( "/[controller]/SignIn" )]
        public IActionResult SignIn()
        {
            var callbackUrl = Url.Action( nameof( OnboardingController.Start ), "Onboarding", values: null, protocol: Request.Scheme );
            var properties = new AuthenticationProperties { RedirectUri = callbackUrl };
            properties.Items[PolicyAuthenticationProperty] = azureAdB2COptions.SignUpSignInPolicyId;

            return this.Challenge( properties, scheme );
        }

The startup.cs code for B2C is unchanged from what the default .NETCore 2.1 template generated for me:

    services.AddAuthentication( AzureADB2CDefaults.AuthenticationScheme )
        .AddAzureADB2C( options =>
        {
            Configuration.Bind( "AzureAdB2C", options );
        } );
John
  • 3,431
  • 7
  • 37
  • 69
  • Could you please provide some details of your policies from the Azure AD B2C blade. Things of interest include :- 1. Sign-up or sign-in policies 2. Sign-up policies 3. Sign-in policies – Mr Slim Jun 15 '18 at 14:46
  • @MrSlim at this point I only have one SignSignUp policy named "B2C_1_susi". I created it using the B2C guide from Microsoft, with no claims other than DisplayName,ObjectID. – John Jun 15 '18 at 14:49

4 Answers4

4

An authentication request that is passed from your web application to Azure AD B2C can contain two redirect URLs:

  1. One (often known as the reply URL) that is passed in the "redirect_uri" parameter, which must be registered with Azure AD B2C, to which all authentication responses are returned from Azure AD B2C to your web application. The default for this is /signin-oidc.
  2. Another (often known as the return URL) that is round-tripped in the "state" parameter, which doesn't have to be registered with Azure AD B2C, to which the end user is returned after your web application has handled the authentication response. An example of this is /Onboarding/Start.

Your web application can set the return URL as follows:

public class AccountController : Controller
{
    public IActionResult SignUp()
    {
        return this.Challenge(
            new AuthenticationProperties()
            {
                RedirectUri = Url.Action("Start", "Onboarding", values: null, protocol: Request.Scheme)
            },
            AzureADB2CDefaults.AuthenticationScheme);
    }
}

The ChallengeResult object creates an authentication challenge for the Azure AD B2C authentication middleware that is added by the AzureADB2CAuthenticationBuilderExtensions.AddAzureADB2C method.

The first argument to the ChallengeResult constructor invokes the OpenID Connect authentication handler that is registered by the Azure AD B2C authentication middleware.

The second argument to this constructor sets the return URL to which the end user will be returned after the Azure AD B2C authentication middleware has handled the authentication response.

Chris Padgett
  • 12,475
  • 1
  • 9
  • 23
  • thanks. I have tried this approach but it does not work unless I use the built-in AccountController in Microsoft.AspNetCore.Authentication.AzureADB2C.UI.AzureADB2C.Controllers.Internal. As soon as I use my own AccountController, the code stops working without any apparent error messages. I also notice that Challenge is a builtin method in the controller base class. Not sure what the difference is between that and using new ChallengeResult(). Both don't work. I can't sign in or out using this approach. Do you know why that might be? I have appended the question with code snippets – John Jun 18 '18 at 10:55
  • Hi @John I've updated the above answer with the `this.Challenge` method. It mightn't be working if you don't pass the `AzureADB2CDefaults.AuthenticationScheme` scheme into this method. – Chris Padgett Jun 27 '18 at 10:15
  • thanks Chris for you help. The this.Challenge method in your sample looks exactly like what I did, the only difference being properties.Items[PolicyAuthenticationProperty] = azureAdB2COptions.SignUpSignInPolicyId – John Jun 27 '18 at 11:33
1

It is my understanding that you will need to enable the the Application Claim -> newUser.

This flag is only set to true when a user initially signs up. Once they are redirected back to your website, you will need to read the claim and redirect to your onboarding/start or other controller if they are an existing user.

enter image description here

Mr Slim
  • 1,333
  • 3
  • 15
  • 26
  • Good catch. Thanks @MrSlim that would solve the second part of my problem. How and where would I hook into the redirect to read the claim? Also, you wouldn't happen to also see why I am getting the correlation error? – John Jun 15 '18 at 15:06
0

You can change the redirect_uri to any action in your website, but the problem is that the uri is only used as an endpoint. The action at the uri is never executed. So I think it will be very hard, if not impossible, to change the routing at the redirect_uri.

But I found another solution to make sure your Onboarding Registration is executed, using the Authorize attribute with a policy like: [Authorize(Policy="HasUserId")]

Take a look at https://stackoverflow.com/a/57672145

Marcel W
  • 2,482
  • 25
  • 42
0
  1. But I am never redirected to the intendend /Start page. instead I land back on the root homepage, just like what happens when I used 'signin-oidc'. Why is that and how do I make it stop going there?

  2. How can I have the Reply URL be different depending on whether you sign IN or UP? I can't really use a sign-up policy for one and a separate sign-in policy for the other, because the reply URL is identical.

I was facing very similar issue to yours. You can have a look at this answer

which says

"The CallbackPath is the path where server will redirect during authentication. It's automatically handled by the OIDC middleware itself, that means we can't control the logic by creating a new controller/action and set CallbackPath to it . Below is the general process :

During authentication, the whole process is controlled by OpenID Connect middleware , after user validate credential in Azure's login page ,Azure Ad will redirect user back to your application's redirect url which is set in OIDC's configuration , so that you can get the authorization code(if using code flow) and complete the authentication process . After authentication , user will then be redirected to the redirect URL ."

Here you can find an example how I managed to handle redirects to different routes after login via AzureAd.

GoldenAge
  • 2,378
  • 4
  • 15
  • 46