1

I'm using ASP.NET Core 5 with Azure AD authentication.

I created a new template web app and sign in and sign out with Azure AD work great.

But when I copied the relevant code in Startup.cs and appsettings.json from the template web app into another web app, I'm getting a 400 error response when I click the Sign Out link to /MicrosoftIdentity/Account/SignOut

["The scheme field is required."]

in Startup.cs, I've added:

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));

and

services.AddRazorPages()
             .AddMicrosoftIdentityUI();

I've compared the requests in the template web app that works and the other web app that doesn't, and I can't see any difference in the request headers to /MicrosoftIdentity/Account/SignOut.

Request headers to /MicrosoftIdentity/Account/SignOut

What "scheme" am I missing?

Joe Wilson
  • 5,591
  • 2
  • 27
  • 38
  • Interesting. :) And there is no exception logged with a helpful stack trace? Because the error message seems to indicates that a `RequiredAttribute` is not satisfied on a `scheme` property of some input model, so validation fails, which would further indicate that some action consuming that model is not executed. – Leaky Mar 05 '21 at 10:02

2 Answers2

1

I looked into the source code of Microsoft.Identity.Web (see here) and MVC, and I think the only reasonable explanation is that you have the nullable reference types C# 8 feature enabled in your second project.

I was able to reproduce the error when I enabled nullables.

What is happening is that the SignOut action has the following attributes and signature:

// From Microsoft.Identity.Web.UI/AccountController.cs
// See: https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web.UI/Areas/MicrosoftIdentity/Controllers/AccountController.cs

/// <summary>
/// Handles the user sign-out.
/// </summary>
/// <param name="scheme">Authentication scheme.</param>
/// <returns>Sign out result.</returns>
[HttpGet("{scheme?}")]
public IActionResult SignOut([FromRoute] string scheme)
{
   ...
}

When you have nullables enabled, this produces the error you observed, because the scheme in the method signature is not optional anymore. The issue is similar to this GitHub issue.

My suspicion is that while nullable support was added to ASP.NET Core and (I suppose) most of its components in 2020, Microsoft.Identity.Web did not get the same treatment (it's actually completely separate from ASP.NET Core; it's part of AzureAD.

What is perhaps more interesting is that why don't the other account actions (having a similar signature) lead to the same error. I don't use neither nullables, nor Microsoft.Identity.Web, so I don't have information pertaining to this.

But of course let me know if I'm wrong, and you don't have nullables enabled. :)

Leaky
  • 3,088
  • 2
  • 26
  • 35
1

After @Leaky's pointer about looking at the Microsoft.Identity.Web SignOut() source code, I changed the Sign Out URL structure to explicitly include the scheme parameter like this:

@if (User.Identity.IsAuthenticated)
{
    var parms = new Dictionary<string, string>
    {
        { "scheme", OpenIdConnectDefaults.AuthenticationScheme }
    };
    <a asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut" 
       asp-all-route-data="parms">
        Sign out
    </a>
}

Now when I hover my mouse over the link, instead of:

https://localhost:44350/MicrosoftIdentity/Account/SignOut

The sign out link looks like this:

https://localhost:44350/MicrosoftIdentity/Account/SignOut/OpenIdConnect

And the full sign out works without error.

Joe Wilson
  • 5,591
  • 2
  • 27
  • 38