Search code examples
.netblazoropenid-connectazure-authentication

Refused to connect. /sign-oidc


In my .NET Blazor application, the after successful authentication using Azure B2C (Azure sign-in log shows 'Success'), the error page is returned with the URL https://localhost: /signin-oidc

Error #1

Error #2

Unfortunately, there are no logs to illuminate the cause of the error.

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
    options.RemoteAuthenticationTimeout = TimeSpan.FromSeconds(10);
    builder.Configuration.Bind("OpenIDConnect", options);

    options.Events = new OpenIdConnectEvents
    {
        OnRedirectToIdentityProvider = async ctxt =>
        {
            logger.Info($"On Redirect To Identity Provider : {ctxt.Request.Host.Value}");
            await Task.Yield();
        },
        OnAuthenticationFailed = async ctxt =>
        {
            logger.Info($"On Authentication Failed");
            Console.WriteLine("On Authentication Failed");
            await Task.Yield();
        },
        OnSignedOutCallbackRedirect = async ctxt =>
        {
            logger.Info($"On Signed Out Callback Redirect");

            ctxt.HttpContext.Response.Redirect(ctxt.Options.SignedOutRedirectUri);
            ctxt.HandleResponse();
            await Task.Yield();
        },
        OnMessageReceived = async ctxt =>
        {
            logger.Info($"On Message Received : {ctxt.Request.Path.Value}");
        },
        OnAuthorizationCodeReceived = async context =>
        {
            logger.Info("Authorization Code Received");

            Console.WriteLine("Authorization Code Received");
        },
        OnTokenValidated = async context =>
        {
            logger.Info("Token Validated");

            Console.WriteLine("Token Validated");
        },
        OnRemoteFailure = async ctxt =>
        {
            logger.Info($"On Remote Failure : {ctxt.Failure?.Message}");
            ctxt.Response.Redirect("/");
            ctxt.HandleResponse();

            Console.WriteLine("On Remote Failure");

        },
        OnTokenResponseReceived = async ctxt =>
        {
            logger.Info($"On Access Denied");

            Console.WriteLine("OnTokenResponseReceived");
        },
        OnTicketReceived = async ctxt =>
        {
            logger.Info($"On Ticket Received : {ctxt.Request.Path.Value}");
         }
        );

The log records OnRedirectToIdentityProvider event, but there is no logs on OnRemoteFailure or OnTokenResponseReceived.

Could you please advise me on how to resolve this error or log it for reference?

Thanks in advance. Any help appreciated.


Solution

  • I created a sample Blazor server (.NET 8) application and successfully authenticated using Azure B2C.

    I referred to this blog for creating the application and configuring Azure B2C authentication.

    Make sure you're defining correct policy name, domain or instance in your appsettings.json

    appsettings.json:

    {
      "AzureAdB2C": {
        "Instance": "https://{ Azure B2C Domain Name}.b2clogin.com/tfp/",
        "ClientId": "<Client-Id>",
        "CallbackPath": "/signin-oidc",
        "Domain": "{ Azure B2C Domain Name}.onmicrosoft.com",
        "SignUpSignInPolicyId": "B2C_1_Blazorsigninsingup",
        "ResetPasswordPolicyId": "",
        "EditProfilePolicyId": ""
      },
        "Logging": {
          "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore": "Warning"
          }
        },
        "AllowedHosts": "*"
      }
    
    • Ensure that ASPNETCORE_ENVIRONMENT is set to Development in the launchSettings.json file
     "https": {
       "commandName": "Project",
       "dotnetRunMessages": true,
       "launchBrowser": true,
       "applicationUrl": "https://localhost:7288;http://localhost:5056",
       "environmentVariables": {
         "ASPNETCORE_ENVIRONMENT": "Development"
       }
    

    program.cs:

    using blazorb2c.Components;
    using Microsoft.AspNetCore.Authentication.OpenIdConnect;
    using Microsoft.Identity.Web.UI;
    using Microsoft.Identity.Web;
    using System.Reflection;
    using System.Security.Claims;
    using System.Linq.Dynamic.Core;
    using blazorb2c.Components;
    namespace BlazorAzureB2C
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                var builder = WebApplication.CreateBuilder(args);
            
                builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                
                var env = builder.Environment;
                builder.Configuration.AddJsonFile($"appsettings{env.EnvironmentName}.json", optional: true);
                builder.Configuration.AddEnvironmentVariables()
                    .AddUserSecrets(Assembly.GetExecutingAssembly(), true);
                     builder.Services.AddRazorComponents()
                    .AddInteractiveServerComponents()
                    .AddMicrosoftIdentityConsentHandler();
                builder.Services.AddCascadingAuthenticationState();
                builder.Services.AddHttpClient();
                builder.Services.AddHttpContextAccessor();
                builder.Services.AddScoped<HttpContextAccessor>();
                            builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                    .AddMicrosoftIdentityWebApp(options =>
                    {
                        builder.Configuration.Bind("AzureAdB2C", options);
                        options.Events = new OpenIdConnectEvents
                        {
                            OnRedirectToIdentityProvider = async ctxt =>
                            {
                                await Task.Yield();
                            },
                            OnAuthenticationFailed = async ctxt =>
                            {
                                
                                await Task.Yield();
                            },
                            OnSignedOutCallbackRedirect = async ctxt =>
                            {
                                ctxt.HttpContext.Response.Redirect(ctxt.Options.SignedOutRedirectUri);
                                ctxt.HandleResponse();
                                await Task.Yield();
                            },
                            OnTicketReceived = async ctxt =>
                            {
                                if (ctxt.Principal != null)
                                {
                                    if (ctxt.Principal.Identity is ClaimsIdentity identity)
                                    {
                                        var colClaims = await ctxt.Principal.Claims.ToDynamicListAsync();
                                        var IdentityProvider = colClaims.FirstOrDefault(
                                            c => c.Type == "http://schemas.microsoft.com/identity/claims/identityprovider")?.Value;
                                        var Objectidentifier = colClaims.FirstOrDefault(
                                            c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;
                                        var EmailAddress = colClaims.FirstOrDefault(
                                            c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress")?.Value;
                                        var FirstName = colClaims.FirstOrDefault(
                                            c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname")?.Value;
                                        var LastName = colClaims.FirstOrDefault(
                                            c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname")?.Value;
                                        var AzureB2CFlow = colClaims.FirstOrDefault(
                                            c => c.Type == "http://schemas.microsoft.com/claims/authnclassreference")?.Value;
                                        var auth_time = colClaims.FirstOrDefault(
                                            c => c.Type == "auth_time")?.Value;
                                        var DisplayName = colClaims.FirstOrDefault(
                                            c => c.Type == "name")?.Value;
                                        var idp_access_token = colClaims.FirstOrDefault(
                                            c => c.Type == "idp_access_token")?.Value;
                                    }
                                }
                                await Task.Yield();
                            },
                        };
                    });
                builder.Services.AddControllersWithViews()
                    .AddMicrosoftIdentityUI();
                var app = builder.Build();
                
                if (!app.Environment.IsDevelopment())
                {
                    app.UseExceptionHandler("/Error");
                    app.UseHsts();
                }
                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseRouting();
                app.UseAuthentication();
                app.UseAuthorization();
                app.MapControllers();
                app.UseAntiforgery();
                app.MapRazorComponents<App>()
                    .AddInteractiveServerRenderMode();
                app.Run();
            }
        }
    }
    

    Add the correct Redirect URI to your Azure B2C app registration as shown below.

    enter image description here

    Check if you are using correct User flow name in the appsettings.json.

    enter image description here

    Now I've successfully authenticated to Azure B2C.

    Output:

    enter image description here

    enter image description here

    enter image description here