DEV Community

Robertino
Robertino

Posted on

🛠 Securing ASP.NET Minimal Web APIs with Auth0

📘 Learn about the new ASP.NET minimal Web APIs introduced in .NET 6.0 and how to secure them with Auth0.


TL;DR: In this article, you will learn how to build minimal Web APIs with .NET 6 and add authorization with JWT access tokens coming from Auth0. The code for this article is available from this GitHub repository.

The Journey to Minimal Web APIs

It has been a long journey since Microsoft released WCF REST Services around 2006 for developing REST services in the .NET framework. This framework did not last long because of the complexities inherited from the WCF programming model and the limited support for using many of the features available in HTTP. It was fine for developing chatty RPC services on top of HTTP, but not more than that.

WCF REST Services was around for a few years until the ASP.NET team introduced ASP.NET Web APIs. This brand new framework resulted from a long collaboration between Microsoft and many experts in the industry.

They also moved away from the term REST, which implied the API implementation should stick to any of the levels in the Richarson's Maturity Model and all the constraints described on it.

The ASP.NET Web APIs framework is still around and has gone through minor refactors over the years and a recent port to .NET Core. However, the ASP.NET team recently announced the availability of minimal Web APIs, a new way to develop and host Web APIs in .NET 6.

This article will discuss many of the improvements and simplifications introduced with minimal Web APIs and a practical example that shows how to implement a TODO list Web API integrated with Auth0 for authentication.

A First Glance at Minimal Web APIs

The best way to show you how a minimal Web API looks like is with code.

var app = WebApplication.CreateBuilder(args).Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Enter fullscreen mode Exit fullscreen mode

That code is a good definition of what the term "minimal" implies. We only required three lines of code to get an API up and running.

The ASP.NET Team removed the friction around configuring APIs and only left the bare bones for running them. It is a top-down approach. They come configured with a basic set of features required to run and let you add more code and features on top as you need.

Where is the Main entry point?

If you noticed, the Program class and Main entry point have gone. That change is part of the new language features introduced with C# 9: Top Level Statements.
Before C# 9, every console program required a namespace and a Program class with a static Main method used as the entry point.
Top Level Statements in C# 9 let you write shorter programs by skipping all those requirements. You can start writing code for your Main method, and the compiler will inject the rest of the code behind the scenes for you.
For the minimal Web API showed before, the resulting code would be equivalent to the following,

namespace APIs 
{
  public class MyProgram 
  {
    public static void Main(params string[] args) 
    {
      var app = WebApplication.CreateBuilder(args).Build();
      app.MapGet("/", () => "Hello World!");
      app.Run();
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

What else from C# 9 and 10?

The good news is that Top Level Statements is not the only feature we could leverage in our minimal Web APIs. We also have "Records", and "File- scoped namespaces". Since we will use them later on, let's discuss those a little more in detail.

Records

A Record is a new reference type, similar to a class or struct but implements value-based equality. That means two different variables of the same record type are equal if the values on every field are the same.
You could accomplish the same thing in the past with a class by overriding the Equals method, but that is no longer necessary with Records. In addition, Records don't need property getters or setters or a constructor to be declared.

The following sample shows a record for a TODO item.

public record TodoItem(string id, string description, bool completed);

var myTodo = new TodoItem("1", "buy milk", false); 
Enter fullscreen mode Exit fullscreen mode

Records are immutable by definition. That means you have to create a copy of a record's instance when any of its properties needs to be changed. C# also offers a language expression for cloning a record and change properties on the way.

var  myTodo = myTodo with { completed = true };
Enter fullscreen mode Exit fullscreen mode

The code above creates a copy of our existing TodoItem but sets the value for the completed property to true.

File- scoped namespaces

Previous versions of C# require you to enclose all your classes and types between "{}" if you wanted to make them part of a namespace. From C# 10 and on, that is no longer a requirement.
You define a top namespace in a file, and all the types in that file will be part of it.

namespace MyNamespace;

public record TodoItem(string name, string description);
Enter fullscreen mode Exit fullscreen mode

In the example above, the record TodoItem will be part of the namespace MyNamespace. We did not have to use any curly brace at all.

Read more...

Discussion (0)