Microsoft.AspNetCore.Identity.SignInManager.GetExternalLoginInfoAsync() returns NULL for AzureAdB2C

180 Views Asked by At

I have setup AzureAdB2C in my .NET Web Application (.NET 7) which is using the Microsoft AspNetCore Identity framework for user management. I followed various sites to implement the solution and came across the recommendation made by Microsoft to use the MIcrosoft Identity Web & Microsoft Identity Web UI packages as implemented here.

I'm also making use of both internal Microsoft Authentication and Azure AD B2C. The Microsoft Account authentication works perfectly but the Azure AD B2C is the one giving me the issue.

My appsettings.json file is configured as below:

{
    "DetailedErrors": true,
    "Logging": {
        "LogLevel": {
            "Default": "Error",
            "Microsoft.AspNetCore": "Error"
        }
    },
    "Microsoft": {
        "AppId": "<client-id>",
        "AppSecret": "<client-secret",
        "AuthEndPoint": "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize",
        "TokanEndPoint": "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token"
    },
    "B2C": {
        "Instance": "https://<domain-id>.b2clogin.com",
        "ClientId": "<client-id>",
        "Domain": "<domain-id>.onmicrosoft.com",
        "SignedOutCallbackPath": "/signout/<b2c_policy_id>",
        "SignUpSignInPolicyId": "<b2c_policy_id>"
    },
    "AllowedHosts": "*"
}

My Program.cs file is configured as below:

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Portal.Interface.Web.Data;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
string connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");

builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false).AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.AddAuthentication()
.AddMicrosoftAccount("Microsoft", "Microsoft", micorosoftOptions =>
{
    micorosoftOptions.AuthorizationEndpoint = builder.Configuration.GetSection("Microsoft").GetValue<string>("AuthEndPoint");
    micorosoftOptions.TokenEndpoint = builder.Configuration.GetSection("Microsoft").GetValue<string>("TokanEndPoint");
    micorosoftOptions.ClientId = builder.Configuration.GetSection("Microsoft").GetValue<string>("AppId");
    micorosoftOptions.ClientSecret = builder.Configuration.GetSection("Microsoft").GetValue<string>("AppSecret");
    micorosoftOptions.AccessDeniedPath = "/Identity/Account/AccessDenied";
})
.AddMicrosoftIdentityWebApp(azureOptions =>
{
    azureOptions.SignInScheme = IdentityConstants.ExternalScheme;
    azureOptions.Instance = builder.Configuration.GetSection("B2C").GetValue<string>("Instance");
    azureOptions.ClientId = builder.Configuration.GetSection("B2C").GetValue<string>("ClientId");
    azureOptions.Domain = builder.Configuration.GetSection("B2C").GetValue<string>("Domain");
    azureOptions.SignedOutCallbackPath = builder.Configuration.GetSection("B2C").GetValue<string>("SignedOutCallbackPath");
    azureOptions.SignUpSignInPolicyId = builder.Configuration.GetSection("B2C").GetValue<string>("SignUpSignInPolicyId");
});

builder.Services.AddRazorPages();
builder.Services.AddAntiforgery(a => a.HeaderName = "XSRF-TOKEN");

WebApplication app = builder.Build();

if (app.Environment.IsDevelopment())
    app.UseMigrationsEndPoint();
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

And my callback endpoint is as follows:

public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        if (remoteError != null)
        {
            ErrorMessage = $"Error from external provider: {remoteError}";
            return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
        }
        var info = await _signInManager.GetExternalLoginInfoAsync(); //Returns null.
        if (info == null)
        {
            ErrorMessage = "Error loading external login information.";
            return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
        }
    //Code omitted...
}

I implemented the IdentityConstants.ExternalScheme under the AddMicrosoftIdentityWebApp options that I picked up in a solution here. But it doesn't seem to resolve the issue.

0

There are 0 best solutions below