Authenticating to Active Directory Federation Services (ADFS) 2019 with .NET Core 3.1

Rory Braybrook
The new control plane
3 min readFeb 6, 2020

Googling this shows only one sample and that sample uses WS-Federation not OpenID Connect (OIDC)!

There doesn’t appear to be anything else and you can’t use the usual ADAL / MSAL libraries because there aren’t .NET Core versions yet.

(There are however, a number of .Net Core samples for accessing Azure AD).

As always, when there’s a vacuum …

I started by creating a MVC ASP.Net Core application in VS 2019 with no authentication.

Then I added code to Startup.cs to enable this.

I used many samples to get this working and found identityserver 4 to be helpful.

(I used “dotnet new is4inmem” from the identityserver4 templates as a reference).

As usual, the code is in the gist.

There may well be extraneous code here but it works against IIS and IIS Express.

I added these NuGet packages.

In the launchSettings.json:

"iisExpress": {
"applicationUrl": "http://localhost:51136",
"sslPort": 44366
}

So using SSL, the URL is:

https://localhost:44366

The OIDC configuration is:

.AddOpenIdConnect(options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:44366";
options.RequireHttpsMetadata = true;
options.ResponseType = OpenIdConnectResponseType.Code;
options.UsePkce = false;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.SaveTokens = true;
// MetadataAddress represents the Active Directory instance used to authenticate users.
options.MetadataAddress = "https://my-adfs/adfs/.well-known/openid-configuration";
options.ClientId = "79ede524-aceb-4824-b25e-a4a8b08e5156";
});

The key points here are the clientID, the well-known discovery endpoint (metadata) and the scopes.

To kick off the authentication, I added the [Authorize] annotation to the home controller.

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using CoreWebApplication.Models;

using Microsoft.AspNetCore.Authorization;

namespace CoreWebApplication.Controllers
{
[Authorize]
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;

public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
...

and I changed privacy.cshtml to display the claims as per the gist.

On the ADFS side, we need to add an application group. This needs to be a “Web browser accessing a web application”.

This generates two parts; a native and a web application.

The native application is configured as below.

Note that the “Client Id” is used to configure the option as above:

options.ClientId = "79ede524-aceb-4824-b25e-a4a8b08e5156";

and the “Redirect URI” derives from the SSL URL as above plus “signin-oidc”.

For the web application, we configure some claims rules:

Now lets run it.

This brings up the ADFS login screen:

We enter our credentials and get redirected back to the application.

Clicking the “Privacy” tab shows:

and

As an exercise, I turned PKCE support on as this is supported in ADFS 2019.

options.UsePkce = true;

It works as expected and you can see the extra parameters (the “code challenge” ones) in the request:

All good!

--

--

Rory Braybrook
The new control plane

NZ Microsoft Identity dude and MVP. Azure AD/B2C/ADFS/Auth0/identityserver. StackOverflow: https://bit.ly/2XU4yvJ Presentations: http://bit.ly/334ZPt5