2

I am successfully using Azure AD and Office365 as a login provider in AspNet-Core Identity by using Microsoft.AspnetCore.Authentication.OpenIdConnect and calling

AddRemoteScheme<OpenIdConnectOptions, OpenIdConnectHandler>("AzureAD","Office 365",_=> { })

I then add a PostConfigureOptions handler for the OpenIdConnectOptions to set it up to work with Azure. This adds a Login with Office 365 button to the login page and is working, but there must be an easier way.

I was curious to see if Microsoft.Identity.Web could be used instead, but am unable to get it to work quite right in my test.

Using the Aspnet-Core templates for dotnet 6 in VS 2022 and selecting individual accounts for authentication you are scaffolded a project with AspNet-Core Identity configured to use an IdentityDbContext with local accounts.

When running the app and logging in, you see an empty list of external authentication providers and a link to Microsoft documentation on adding external authentication providers here:

https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/?view=aspnetcore-6.0&tabs=visual-studio

To test the Microsoft.Identity.Web package, I am calling:

builder.Services.AddAuthentication().AddMicrosoftIdentityWebApp(config.GetSection("AzureAD"))

in Programs.cs

This works to add the authentication provider and I now get an "OpenIdConnect" button under "Use another service to log in". Clicking it results in a failure "Error loading external login information."

When trying to login by clicking the button, I receive "Error loading external login information.". Line 107 in ExternalLogin.cshtml.cs from Microsoft's Identity UI is always null:

var info = await _signInManager.GetExternalLoginInfoAsync();

Is it possible to provide the right arguments to .AddMicrosoftIdentityWebApp() such that it works with AspNet-Core Identity as an external authentication provider using minimal code and configuration?

Steve
  • 596
  • 2
  • 7
  • 20
  • What's wrong with [`AddMicrosoftAccount`](https://github.com/MintPlayer/MintPlayer/blob/master/MintPlayer.Web/Startup.cs#L219)? – Pieterjan Mar 04 '22 at 21:46
  • I want to use the Azure AD backing my clients Office365 instances for the line of business web apps I create for them. Some of apps require local accounts and I currently use Office365 as a login provider by using .AddAzureAD(options => Configuration.Bind("AzureAd", options)) from Microsoft.AspNetCore.Authentication.AzureAD.UI v6.0.0 but wanted to know if there was a working Microsoft Identity Platform equivalent, or if this is still the right way,. – Steve Mar 04 '22 at 22:22

1 Answers1

3

After working through the source, the solution was simple. Here is a working extension method that will configure Microsoft.Identity.Web for use as an eternal authentication provider with AspNet-Core Identity:

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddOffice365Identity<TContext,TUser>(
        this IServiceCollection services,
        IConfigurationSection config,
        Action<IdentityOptions>? options = null)
          where TContext : IdentityDbContext
          where TUser : class
    {

      //Setup Default Identity
      var identityBuilder = options == null ?
        services.AddDefaultIdentity<TUser>()
        : services.AddDefaultIdentity<TUser>(options);
    
      identityBuilder.AddEntityFrameworkStores<TContext>();

     //Add Microsoft.Identity.Web 
     services
        .AddAuthentication()
        .AddMicrosoftIdentityWebApp(config,displayName: "Office 365")
        .EnableTokenAcquisitionToCallDownstreamApi()
        .AddMicrosoftGraph()
        .AddInMemoryTokenCaches();

      //This is the important part: Change the SignInScheme to External
      //After ALL other configuration have run.
      //Claim mapper maps all claims and adds the ClaimTypes.Email claim.
      services
        .AddOptions()
        .PostConfigureAll<OpenIdConnectOptions>(o => {
        o.SignInScheme = IdentityConstants.ExternalScheme;            
        o.ClaimActions.Add(new ClaimMapper());
      });

      return services;
  }
}

Running this you will end up with a working "Office 365" configuration assuming your appconfig has the usual:

"AzureAd": {
  "CallbackPath": "/signin-oidc",
  "ClientSecret": "[client_secret]",
  "ClientId": "[client_id]",
  "Domain": "[domain]",
  "Instance": "https://login.microsoftonline.com/",
  "SignedOutCallbackPath": "/signout-callback-oidc",
  "TenantId": "[Tenant Id]"
}
Steve
  • 596
  • 2
  • 7
  • 20
  • Hi @Steve, claimmapper is that a custom method? – Gmorken Oct 19 '22 at 06:14
  • Sorry, I have changed jobs and don't have access to the source. From what I recall, I created a custom mapper by deriving from ClaimAction and implementing run as per https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/additional-claims?view=aspnetcore-6.0#create-and-add-claims "Users can define custom actions by deriving from ClaimAction and implementing the abstract Run method." Hope that helps! – Steve Oct 20 '22 at 13:15
  • I wouldn't have gotten this in 100 million years. Learning Microsoft identity is like trying to find a specific grain of rice located somewhere in New York. Thank you very much – dgo Aug 08 '23 at 17:44