.NET Core 3.0 (Preview 4) Web API Authentication from Scratch (Part 3): Token Authentication

JSON Web Tokens (JWT)

Nishān Wickramarathna
6 min readMay 9, 2019
How JWT works ( Image courtesy of Espeo Software)

Now we have the Auth Repository available (follow part 1 and part 2 of this series) for us to use. Let’s go ahead and create AuthController inside Controllers directory.

Note: This article is originally written for .NET Core 3.0 (Preview 4), so in some places you will see —- version flag when I install packages. Feel free to install the latest version by removing the —- version flag, newer versions should work as expected. As an example you can use dotnet add package System.IdentityModel.Tokens.Jwt instead of dotnet add package System.IdentityModel.Tokens.Jwt — version 5.4.0

Note 2: I have updated the project to .NET 5.0 can be accessed from following URL. It’s not a frustrating process, as mentioned earlier make sure packages are at latest version.

We also need a route so the client applications will call in. <host url>/api/auth will be our endpoint so we’ll add the route as api/[controller] , also we need to inject AuthRepository. Here’s how it looks like,

Let’s create Register method. This is gonna be a [HttpPost] because we need to get information from the users.

DTOs

We will be passing username and password as a JSON serialized object. To get username and password from that serialized object, we need to create an object that will resemble the incoming massage. DTOs (Data Transfer Objects) are a way of doing this. Take a look.

Create a new folder called Dtos and inside create new class UserForRegisterDto with fields, string username and string password

Final Register method looks like this. make sure to add these namespaces at the top.

using System.Threading.Tasks;
using JWTAuth.API.Models;
using JWTAuth.API.Dtos;

Final AuthController with register method looks like this.

We are converting the username to lowercase because somebody may use “John” as username and somebody else will use “john” with lowercase ‘j’. So there could be two johns. We don’t want that scenario. So before storing it in the database we are converting everything to lowercase. When our API checks for existing usernames using UserExists() later, it will work as expected.

Now let’s send a postman request and see if we did it correctly.

Note that the endpoint is https://localhost:5001/api/auth/register [1], and it is a POST request [2]. You also need to add a header with Content-Type with value as application/json [3] make sure you have set the body content as Json [4] and type the request in this format [5].

{
"username": "John",
"password": "password123"
}

Which will result in 201 Created status code [6] as we set in our AuthController

return StatusCode(201);

Take a look at the database to see if the user has been created.

Let’s add some additional validation for our API. Go to UserForRegisterDto and change code as follows. Don’t forget to add namespace,

using System.ComponentModel.DataAnnotations;

This will make username and password as required fields and password rules. Let’s send empty object in postman to test it out.

{
"username": "",
"password": ""
}

See, we get error messages.

Token Authentication

Next we will look at Login method. When a user logs in we need to send an authentication token to the user. We will be using JWT or JSON Web Tokens to do that. Learn more about JWT

Again let’s create a DTO for login as UserForLoginDto in Dtos folder.

Now let’s create Login method. First we are getting the user from repository. If user login failed we will return 401 Unauthorized . Next part will create a JWT token as an object to the caller of this login method.

First install System.IdentityModel.Tokens.Jwt from CLI

dotnet add package System.IdentityModel.Tokens.Jwt --version 5.4.0

Add following namespace to the top of AuthController .

using Microsoft.Extensions.Configuration;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using System;

Add a section to appsettings.json with a secret key with this format. In my case, the key is “secret key for jwt”.

"AppSettings":{
"Token": "secret key for jwt"
}

Now for this to be used in AuthController we need to inject it. Just like we did to AuthRepository .

private readonly IAuthRepository _repo;
private readonly IConfiguration _config;
public AuthController(IAuthRepository repo, IConfiguration config)
{
_repo = repo;
_config = config;
}

And the login method.

Full AuthController.

Let’s send a postman request to https://localhost:5001/api/auth/login [1] to see if that works,

Note that it is a POST request with headers application/json having a JSON body,

{
"username": "John",
"password": "password123"
}

with the user that we registered earlier, which returns status code 200 Ok with tokenString . You can copy this token and go to https://jwt.io and decode it.

In payload you will see nameid as 1 and unique_name as john. This is because we told the token to return those information with the token when we add Claims.

Subject = new ClaimsIdentity(new Claim[]{
new Claim(ClaimTypes.NameIdentifier,userFromRepo.Id.ToString()),
new Claim(ClaimTypes.Name, userFromRepo.Username)
}),

Now we need to specify other methods which are not allowed to be accessed without the token. The ValuesController we created in the first part of this article still can be accessed without logging in.

Let’s made it restricted, so without the token it cannot be accessed.

Authentication Middleware

First install this package using CLI,

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 2.2.0

Then go to Startup.cs add these lines to ConfigureServices method.

var key = Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});

Full Startup.cs looks like this. Full csproj file looks like this.

Add these namespaces to the top,

using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using System.Text;

In Configure method, make sure you have app.UseAuthentication(); after app.UseRouting(); [Note — app.UseAuthentication(); and app.UseAuthorization(); are two different things.]

Add,

using Microsoft.AspNetCore.Authorization;

namespace to the top of ValuesCotroller. Then add [Authorize] attribute to the specific method or for entire controller. I’ll add it to the controller.

Now, if you send the GET request to https://localhost:5001/api/values it will return 401 Unauthorized that’s because you need to send the token with the request.

Send login request again and get a token. Go back to postman, add a new header Authorization with value Bearer <token> , note that there’s a space between bearer and token.

Done!. You have successfully implemented token authentication in .net core!

Visit here to get full code for this project. Hope you learnt something from this 3 articles. Happy coding!! :)

Consider helping me out!

--

--