Skip to content

Step by Step Instruction (ASP.NET core 2.0)

CodeGx edited this page Apr 2, 2018 · 5 revisions
  1. Install Microsoft.Identity.Client in your NuGet package manager: The package is currently in preview so you need to check Include prerelease to search for it. This is the package which makes it easier to obtain tokens from Microsoft Azure AD B2C.
  2. Modify appsettings.json: add the following configuration details for Azure AD B2C.
"Authentication": {
    "AzureAdB2C": {
      "Tenant": "dnvglb2ctest.onmicrosoft.com",
      "TenantId": "ed815121-cdfa-4097-b524-e2b23cd36eb6",
      "ClientId": "**Your Client ID**",
      "ClientSecret": "**Your Client Secret**",
      "RedirectUri": "https://localhost:44330/signin-oidc",  
      "SignUpSignInPolicyId": "B2C_1A_SignInWithADFSIdp",
      "ResetPasswordPolicyId": "B2C_1A_SignInWithADFSIdp",
      "EditProfilePolicyId": "B2C_1A_SignInWithADFSIdp",
      "ApiUrl": "https://myapiv3test.dnvgl.com",
      "ApiScopes": "https://dnvglb2ctest.onmicrosoft.com/a4a8e726-c1cc-407c-83a0-4ce37f1ce130/user_impersonation"
    }
  },
  "VeracityService": {
    "HostName": "https://myapiv3test.dnvgl.com",
    "Identifier": "https://dnvglb2ctest.onmicrosoft.com/a4a8e726-c1cc-407c-83a0-4ce37f1ce130", 
    "ServiceId": "**Your Service ID**"
  }
  1. Create a class to map your settings:
public class AzureAdB2COptions
    {
        public const string PolicyAuthenticationProperty = "Policy";

        public AzureAdB2COptions()
        {
            AzureAdB2CInstance = "https://login.microsoftonline.com";
        }

        public string ClientId { get; set; }
        public string AzureAdB2CInstance { get; set; }
        public string Tenant { get; set; }
        public string TenantId { get; set; }
        public string SignUpSignInPolicyId { get; set; }
        public string SignInPolicyId { get; set; }
        public string SignUpPolicyId { get; set; }
        public string ResetPasswordPolicyId { get; set; }
        public string EditProfilePolicyId { get; set; }
        public string RedirectUri { get; set; }

        public string DefaultPolicy => SignUpSignInPolicyId;
        public string Authority => $"{AzureAdB2CInstance}/tfp/{Tenant}/{DefaultPolicy}/v2.0";
        public string ClientSecret { get; set; }
        public string ApiUrl { get; set; }
        public string ApiScopes { get; set; }
        public string MicrosoftGraphScope { get; set; }
        public string MicrosoftGraphQuery { get; set; }
    }

4.Edit Startup.cs: Add the following code. Ignore the error for now. In the ConfigureServices method

services.Configure<MvcOptions>(options =>
	{
		options.Filters.Add(new RequireHttpsAttribute());
	});

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

services.AddAuthentication(sharedOptions =>
	{
		sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
		sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
	})
	.AddAzureAdB2C(options => Configuration.Bind("Authentication:AzureAdB2C", options))
	.AddCookie();

In the Configure method

app.UseSession();
app.UseAuthentication();
  1. Create a class to setup openid:
public static class AzureAdB2CAuthenticationBuilderExtensions
    {
        public static AuthenticationBuilder AddAzureAdB2C(this AuthenticationBuilder builder)
            => builder.AddAzureAdB2C(_ =>
            {
            });
 
        public static AuthenticationBuilder AddAzureAdB2C(this AuthenticationBuilder builder, Action<AzureAdB2COptions> configureOptions)
        {
            builder.Services.Configure(configureOptions);
            builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, OpenIdConnectOptionsSetup>();
            builder.AddOpenIdConnect();
            return builder;
        }
 
        public class OpenIdConnectOptionsSetup : IConfigureNamedOptions<OpenIdConnectOptions>
        {
 
            public OpenIdConnectOptionsSetup(IOptions<AzureAdB2COptions> b2cOptions)
            {
                AzureAdB2COptions = b2cOptions.Value;
            }
 
            public AzureAdB2COptions AzureAdB2COptions { get; set; }
 
            public void Configure(string name, OpenIdConnectOptions options)
            {
                options.ClientId = AzureAdB2COptions.ClientId;
                options.Authority = AzureAdB2COptions.Authority;
                options.UseTokenLifetime = true;
                options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "userId" };
 
                options.Events = new OpenIdConnectEvents()
                {
                    OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
                    OnRemoteFailure = OnRemoteFailure,
                    OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
                };
            }
 
            public void Configure(OpenIdConnectOptions options)
            {
                Configure(Options.DefaultName, options);
            }
 
            public Task OnRedirectToIdentityProvider(RedirectContext context)
            {
                var defaultPolicy = AzureAdB2COptions.DefaultPolicy;
                if (context.Properties.Items.TryGetValue(AzureAdB2COptions.PolicyAuthenticationProperty, out var policy) &&
                    !policy.Equals(defaultPolicy))
                {
                    context.ProtocolMessage.Scope = OpenIdConnectScope.OpenIdProfile;
                    context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken;
                    context.ProtocolMessage.IssuerAddress = context.ProtocolMessage.IssuerAddress.ToLower().Replace(defaultPolicy.ToLower(), policy.ToLower());
                    context.Properties.Items.Remove(AzureAdB2COptions.PolicyAuthenticationProperty);
                }
                else if (!string.IsNullOrEmpty(AzureAdB2COptions.ApiUrl))
                {
                    context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}";
                    context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.CodeIdToken;
                }
                return Task.FromResult(0);
            }
 
            public Task OnRemoteFailure(RemoteFailureContext context)
            {
                context.HandleResponse();
                // Handle the error code that Azure AD B2C throws when trying to reset a password from the login page 
                // because password reset is not supported by a "sign-up or sign-in policy"
                if (context.Failure is OpenIdConnectProtocolException && context.Failure.Message.Contains("AADB2C90118"))
                {
                    // If the user clicked the reset password link, redirect to the reset password route
                    context.Response.Redirect("/Session/ResetPassword");
                }
                else if (context.Failure is OpenIdConnectProtocolException && context.Failure.Message.Contains("access_denied"))
                {
                    context.Response.Redirect("/");
                }
                else
                {
                    context.Response.Redirect("/Home/Error?message=" + context.Failure.Message);
                    //context.Response.Redirect("/Home/Error?message=" + "unauthorized");
                }
                return Task.FromResult(0);
            }
 
            public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                // Use MSAL to swap the code for an access token
                // Extract the code from the response notification
                var code = context.ProtocolMessage.Code;
 
                string signedInUserID = context.Principal.FindFirst("userId")?.Value;
                TokenCache userTokenCache = new MSALSessionCache(signedInUserID, context.HttpContext).GetMsalCacheInstance();
                ConfidentialClientApplication cca = new ConfidentialClientApplication(AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null);
                try
                {
                    AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, AzureAdB2COptions.ApiScopes.Split(' '));
 
 
                    context.HandleCodeRedemption(result.AccessToken, result.IdToken);
                }
                catch (Exception ex)
                {
                    //TODO: Handle
                    throw;
                }
            }
        }
    }
Clone this wiki locally