Month: February 2020

App Service Easy Auth with Auth0 (or any Open ID Connect provider)

So I’m going to prefix this with a warning – I doubt this is officially supported but at a basic level it does seem to work. I would use at your peril and I’m writing this in the hope that it makes for a useful starting point discussion with the App Service team.

I was looking at Easy Auth this week and found myself curious as to if it would work with a generic Open ID Connect identity provider. My first choice provider is Auth0 but that’s not one of the listed providers on the Easy Auth configuration page which, on the face of it, is quite limited:

Azure AD is (as well as many other things) an Open ID Connect Provider so I had a look at its settings in the advanced tab and its asking for two pretty common pieces of information in the identity world: a client ID and an issuer URL. I had an app in Auth0 that I use for general testing so I pasted in its well known configuration endpoint and the ID for my client:

I hit save and it seemed to accept everything. My web app is sat on the URL https://jdreasyauth0.azurewebsites.net/ so on the Auth0 side I added a callback URL to the Easy Auth callback endpoint:

Easy Auth forwards on the contents of common claims in headers such as X-MS-CLIENT-PRINCIPAL-ID (the subject) and X-MS-CLIENT-PRINCIPAL-NAME (the name) so to see if this was working I uploaded a simple ASP.Net Core app that would output the contents of the request headers to a web page. Then I paid it a visit in my browser:

Oh. So that’s hurdle one passed. It does redirect successfully to a none-Azure AD identity provider. What about logging in?

Great. Yes. This works too. And the headers are correct based on the identity I used to login with.

How does this compare to the headers from an Azure AD backed Easy Auth:

Basically the Auth0 login is missing the refresh token (I did later set a client secret and tweak configuration in Auth0) – so there might be some work needed there. But I don’t think that’s essential.

It would be incredibly useful to be able to use Easy Auth in a supported manner with other identity providers – particularly for Azure Functions where dealing with token level authorization is a bit more “low level” than in a fully fledged framework like ASP .Net Core (though my Function Monkey library can help with this) and is only dealt with after a function invocation.

Using Function Monkey with MediatR

There are a lot of improvements coming in v4 of Function Monkey and the beta is currently available on NuGet. As the full release approaches I thought it would make sense to introduce some of these new capabilities here.

In order to simplyify Azure Functions development Function Monkey makes heavy use of commanding via a mediator and ships with my own mediation library. However there’s a lot of existing code out their that makes use of the popular MediatR library which, if Function Monkey supported, could fairly easily be moved into a serverless execution environment.

Happily Function Monkey now supports just this! You can use my existing bundled mediator, bring your own mediator, or add the shiny new FunctionMonkey.MediatR NuGet package. Here we’re going to take a look at using the latter.

First begin by creating a new, empty, Azure Functions project and add three NuGet packages:

FunctionMonkey
FunctionMonkey.Compiler
FunctionMonkey.MediatR

At the time of writing be sure to use the prerelease packages version 4.0.39-beta.4 or later.

Next create a folder called Models. Add a class called ToDoItem:

public class ToDoItem
{
    public Guid Id { get; set; }
    
    public string Title { get; set; }
    
    public bool IsComplete { get; set; }
}

Now add a folder called Services and add an interface called IRepository:

internal interface IRepository
{
    Task<ToDoItem> Create(string title);
}

And a memory based implementation of this called Repository:

internal class Repository : IRepository
{
    private readonly List<ToDoItem> _items = new List<ToDoItem>();
    
    public Task<ToDoItem> Create(string title)
    {
        ToDoItem newItem = new ToDoItem()
        {
            Title = title,
            Id = Guid.NewGuid(),
            IsComplete = false
        };
        _items.Add(newItem);
        return Task.FromResult(newItem);
    }
}

Now create a folder called Commands and in here create a class called CreateToDoItemCommand:

public class CreateToDoItemCommand : IRequest<ToDoItem>
{
    public string Title { get; set; }
}

If you’re familiar with Function Monkey you’ll notice the difference here – we’d normally implement the ICommand<> interface but here we’re implementing MediatR’s IRequest<> interface instead.

Next create a folder called Handlers and in here create a class called CreateToDoItemCommandHandler as shown below:

internal class CreateToDoItemCommandHandler : IRequestHandler<CreateToDoItemCommand, ToDoItem>
{
    private readonly IRepository _repository;

    public CreateToDoItemCommandHandler(IRepository repository)
    {
        _repository = repository;
    }
    
    public Task<ToDoItem> Handle(CreateToDoItemCommand request, CancellationToken cancellationToken)
    {
        return _repository.Create(request.Title);
    }
}

Again the only real difference here is that rather than implement the ICommandHandler interface we implement the IRequestHandler interface from MediatR.

Finally we need to add our FunctionAppConfiguration class to the root of the project to wire everything up:

public class FunctionAppConfiguration : IFunctionAppConfiguration
{
    public void Build(IFunctionHostBuilder builder)
    {
        builder
            .Setup(sc => sc
                .AddMediatR(typeof(FunctionAppConfiguration).Assembly)
                .AddSingleton<IRepository, Repository>()
            )
            .UseMediatR()
            .Functions(functions => functions
                .HttpRoute("todo", route => route
                    .HttpFunction<CreateToDoItemCommand>(HttpMethod.Post)
                )
            );
    }
}

Again this should look familiar however their are two key differences. Firstly in the Setup block we use MediatR’s IServiceCollection extension method AddMediatR – this will wire up the request handlers in the dependency injector. Secondly the .UseMediatR() option instructs Function Monkey to use MediatR for its command mediation.

And really that’s all their is to it! You can use both requests and notifications and you can find a more fleshed out example of this on GitHub.

As always feedback is welcome on Twitter or over on the GitHub issues page for Function Monkey.

Contact

  • If you're looking for help with C#, .NET, Azure, Architecture, or would simply value an independent opinion then please get in touch here or over on Twitter.

Recent Posts

Recent Tweets

Recent Comments

Archives

Categories

Meta

GiottoPress by Enrique Chavez