Minimal APIs are all the rage these days. Python and Node.js have had a much simpler model for creating APIs for a while. And now .NET 6 joins this trend - which is a welcome change. I streamed about this on our 425Show Twitch channel so if you prefer video over text, you can watch all the action on our YouTube channel:
Prerequisites
You'll need the following to follow along:
- .NET 6 Preview 7 (as of writing this blog post)
- Visual Studio Code (or any other .NET IDE)
- And Azure AD B2C (as part of your Azure subscription - get a free one here)
Create the Azure AD B2C App
We'll start by creating the two App Registrations needed for our API and our API client. In the Azure AD B2C portal, navigate to the App Registrations blade and create a new one by clicking on the + New Registration. Give it a meaningful name, leave the default for Supported Account Types and press Register. In the newly created App Registration, navigate to the Expose an API and Set the Application ID URI.
We can now add a Scope. Since we'll be pulling weather data, we can use something like Weather.Read
for the scope name.
Take a note of the following information:
- Application (Client) ID (App Registration Overview Tab)
- Azure AD B2C Instance name (e.g https://[YourB2CName].b2clogin.com)
- B2C Domain (e.g [YourB2CName].omicrosoft.com)
- User flow name (e.g B2C_1_susi)
Using Thunder Client in VS Code to test a secure API
What good is it if we can't test/use our secure API? When I work with APIs, I like to use Thunder Client, a VS Code extension that provides a GUI based REST Client. Unlike Postman, I don't have to install it on every machine and it is available in CodeSpaces too! For Thunder Client to be able to call an Azure AD B2C secure API we we need a client API App Registration. Let's do this!
Create a new App Registration, give it a meaningful name and press Register. Then navigate to the Authentication tab and press the + Add a platform button. Make sure to select Web and add the following for the Redirect URI: https://www.thunderclient.io/oauth/callback
. This is the URL that Thunder Client is expecting to receive the Access Token.
Next, navigate to the Certificates & Secrets tab and create a new secret. Make sure to copy it as we'll need it to configure Thunder Client.
Finally, we need to add our API permissions. Navigate to the API permissions tab and press the Add a permission. Select My APIs, find the name of the App Registration you created at the previous step and select it.
Expand the permissions, select the name of your permission (in your case it should be Weather.Read
). Then press the Add Permission button.
The final, and most important, step in the process is to give Admin Consent to our custom API Permission.
The information we need from this App Registration is:
- Application (Client) ID (App Registration Overview Tab)
- Auth endpoint (e.g https://cmatdevb2c.b2clogin.com/cmatdevb2c.onmicrosoft.com/YourB2CPolicyName/oauth2/v2.0/authorize
- Token endpoint (e.g https://cmatdevb2c.b2clogin.com/cmatdevb2c.onmicrosoft.com/YourB2CPolicyName/oauth2/v2.0/token)
- Client Secret
- API Permission (e.g https://cmatdevb2c.onmicrosoft.com/b332fc47-cfff-4f57-bb0f-7b6ccea75521/weather.read)
In Thunder Client, create a new Request and navigate to the Auth tab, select OAuth2 and configure the settings as shown in the pic below:
We can now test it out. If all is configured correctly, you should see the following:
Create and secure the minimal API
Open your favorite terminal (mine is Windows Terminal) and type the following:
dotnet new webapi --auth IndividualB2C
The template does most of the work for us, but we can tweak the code to make it truly minimal! Update your Program.cs
to look like this
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
using MinimalAPIWithB2C2;
string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, "AzureAdB2C");
builder.Services.AddAuthorization();
builder.Services.AddCors(options => options.AddPolicy("allowAny", o => o.AllowAnyOrigin()));
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() { Title = "MinimalAPIWithB2C2", Version = "v1" });
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MinimalAPIWithB2C2 v1"));
}
app.MapGet("/weatherforecast",(HttpContext context) =>
{
context.VerifyUserHasAnyAcceptedScope(new[] {"access_as_user"});
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}).RequireAuthorization();
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
We can now delete the Controllers folder and all it's contents. Finally, we need to update the appsettings.json
with the info we collected from the first step when we created the API App Registration. Your appsettings.json
should look like this:
{
"AzureAdB2C": {
"Instance": "https://<yourB2CName>.b2clogin.com/tfp/",
"ClientId": "<your client id>",
"Domain": "<yourB2CName>.onmicrosoft.com",
"SignUpSignInPolicyId": "B2C_1_susi"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
The policy name needs to match in both your API and your Thunder Client settings.
Let's build and run the API so that we can test it :)
dotnet build
dotnet run
Then, let's switch to Thunder Client in VS Code and send a GET request to our API endpoint: https://localhost:5001/weatherforecast
. If everything was configured correctly, we should receive the following output from the API:
Show me the Code!!
If you want to go straight to the source code, check out our working sample in the 425Show Github repo
Summary
I really dig the new minimal API templates in .NET 6. And although this approach may not be for everyone, I can totally see the appeal. Also note that you don't have to stick with this design and you can refactor your code out to separate files to keep your files small and concise. Controllers are here to stay! In the end, it all comes down to personal preference and what works best for you and your team.
Top comments (5)
Hi,
Could you fix links to images please?
Hmmm, all images are working for me
I see a lot of ALT TEXT and 404 in Network console. (EDGE browser)
Request URL: res.cloudinary.com/practicaldev/im...
Request Method: GET
Status Code: 404 Not Found
Unfortunately this is a hosted service and the images are hosted on an S3 bucket that dev.to manages. No idea why the images here would be failing :(
Thanks man! Really appreciate the knowledge you share with the developer community.