Secure your ASP.NET Core 2.0 API (part 2 - restrict access to JWT bearers only)

Published on

Your API is wide open

If you read part 1, you know now what a JWT is and how to issue one.

We’ve provided a convenient way for clients to gain access to restricted areas of our API

… but, we haven’t actually restricted anything.

If you leave your API open like this, your SPA can make requests to it, but so can anyone else.

As a minimum we want to ensure the client making a request to our API has a valid token (which they got by calling our JWT-issuing action, with a valid username and password).

The plan

Our plan of attack:

  1. Require authentication for our API controllers
  2. Test that anonymous requests are rejected
  3. Configure JWT auth in startup.cs
  4. Test that requests with a valid JWT are accepted

Require Authentication

With the [Authorize] attribute you can easily lock down your API to authorized users only.

[Authorize]
[Route("api")]
public class ApiController : Controller
{
[HttpGet("Test")]
public IActionResult Test()
{
return Ok("Super secret content, I hope you've got clearance for this...");
}
// rest of controller goes here
}

Now, unless otherwise specified, every action in this controller will require the request to be authenticated.

Test anonymous requests

Try navigating to your http://yourapihere/api/test and you’ll get a 401 Unauthorized response.

NOTE

Check your work

Whilst it’s become a little bloated in recent times, Postman is still a handy tool for testing your site.

In this case, if you want to try hitting your API, you can easily create a GET request, run it, then check what status code comes back (401 hopefully).

So our API is definitely secure, but now we have the opposite problem to before, no one can get past this barrier.

Authenticate JWTs

In ASP.NET Core 2.0, configuring JWT auth is pretty straightforward.

In most cases, you just need to configure it in startup.cs.

public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "yourdomain.com",
ValidAudience = "yourdomain.com",
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["SecurityKey"]))
};
});
services.AddMvc();
}

These are the basic options for configuring JWT auth for your site.

This code configures ASP.NET Core so that requests to API actions (which require authentication) will check for a token meeting these requirements:

If you’re wondering where _configuration came from (it may be missing in your startup.cs file), you can easily bring it in via the constructor and let ASP.NET Core wire it up for you.

public Startup(IConfiguration configuration)
{
_configuration = configuration;
}

Whilst you’re here you’ll also need to add one line to the Configure method in startup.cs.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
app.UseStaticFiles();
}

Your Configure method may vary but the key part is adding app.UseAuthentication();.

This needs to be one of the first lines (and definitely before UseMvc) so it takes effect early in the pipeline and stops ASP.NET Core from serving the request as soon as possible if the user isn’t authorised.

Test valid requests

Now to the final hurdle, can we get to our test API method if we pass a valid token?

First up, we can hit the API action we created in part 1, to get a JWT.

Then modify the headers for our API GET request, to pass that token in the Authorization header.

Authorization: Bearer <token goes here>

So now what?

You can issue a JWT and validate it. Your app is now protected from meddling by anonymous users.

This approach is known as Bearer Token Authentication where your app issues a token and then gives access to the bearer of that token.

If you have a valid token, you’re in.

Photo Credits:

Jez B Fairly pointless… via photopin (license)

Theo Crazzolara Stop, it’s winter via photopin (license)

All posts in Secure your ASP.NET Core Web API
  1. Identify users and their permissions with JWTs and ASP.NET Core WebAPI
  2. Secure your ASP.NET Core 2.0 API (part 1 - issuing a JWT)
  3. Tackle more complex security policies for your ASP.NET Core app
  4. Secure your ASP.NET Core 2.0 API (part 2 - restrict access to JWT bearers only)

I know you don't have endless hours to learn ASP.NET

Cut through the noise, simplify your web apps, ship your features. One high value email every week.

I respect your email privacy. Unsubscribe with one click.

    Next Up
    1. Secure your ASP.NET Core 2.0 API (part 1 - issuing a JWT)
    2. How to get data from an HTML form to your ASP.NET MVC Core Controller
    3. Keep your ASP.NET Core secrets safe in production using Azure Application Settings