Angular and the REST - Authentication with JWT
Published: 2019-07-19 17:20:43

In this second installment of the series on Angular and the REST, I implement authentication on the backend ASP.NET Core Web API using JWT (JSON Web Token). In addition, I add a new authentication module on the Angular app side, so access is restricted to authenticated users only by way of a Login.

Let's recap what we have achieved so far in this series. We built the backend ASP.NET Core Web API app that defines a Movie Tracker Endpoint with a full implementation of the CRUD actions and movie search. On the client-side, we built an Angular v8 app that communicates with the backend RESTful Web API by means of a Movie Tracker Service that we generated using Swagger API Documentation, NSwag and NSwagStudio. The app displays all movies, allows the user to filter the movies, adds a new movie, edits an existing movie and can delete a movie.

Here’s a link to the first article in this series [Angular and the REST]().

Today, let's start first by adding JWT authentication to our ASP.NET Core Web API.

## Adding JWT Authentication to ASP.NET Core Web API 
To start building Web APIs with ASP.NET Core, make sure you have the following tools and frameworks locally installed on your machine.

- .NET Core 2.2 Framework [Download](https://dotnet.microsoft.com/download/dotnet-core/2.2)
- Visual Studio 2019 [Download](https://visualstudio.microsoft.com/vs/)

We, for all intents and purposes, will be developing this app on a Windows machine. Feel free to use a Macbook or any other machine you like.

In the remaining part of this section, we will go through a step by step guide on how to add JWT authentication to the ASP.NET Core Web API app.

The source code for the backend Web API can be found on this Github [repo](https://github.com/bhaidar/movietracker-server/tree/jwt-authentication).

**Step 1**
To start authenticating users in our app we need to first start managing users. Therefore, let's amend the **MovieTrackerContext** to cater to Users in our app.

Change the header of the context class to look like this:

```c#
public class MovieTrackerContext : IdentityDbContext<ApplicationUser>
```
By inheriting from **IdentityDbContext** class we guarantee that Entity Framework (EF) Core will create all the necessary User-related tables in the database.

The IdentityDbContext requires a User class defined in the application in order to create the Users table in the database. By default, the IdentityDbContext class makes use of the IdentityUser that defines a number of standard User fields as follows:

{% gist https://gist.github.com/bhaidar/9e73bbf0ab16991ac1d8513790c2f739 %}

In general, you can use the IdentityUser as long as you are satisfied by the fields defined. However, if you want to manage more fields, you can create a new class, inherit from the IdentityUser and add any additional fields.

For the sake of this demonstration, let's create a new **ApplicationUser** class inheriting from IdentityUser as follows:

```c#
public class ApplicationUser : IdentityUser
{ }
```

For this article, we won't be adding any additional fields.

**Step 2**
Let's register the User Management services inside the **Startup** class as follows:

{% gist https://gist.github.com/bhaidar/bce6a993bfb156324c6f76a9027059a4 %}

With this registration, the **UserManager** class is now available to use in the application to manage and authenticate users. The UserManager will use the MovieTrackerContext class to connect to the database and store all users' data.

**Step 3**
Creating users is outside the scope of this article. Therefore, I will seed a user record and base our tests on this user.

Add a new **Models\SeedUser.cs** file with the following content:

{% gist https://gist.github.com/bhaidar/7e47ee241152592078e989d849d6ce72 %}
The code defines a static **Initialize** method that starts by retrieving a MovieTrackerContext and UserManager instance respectively from the ASP.NET Core Dependency Injection system.

Then, it checks the Users table to confirm whether or not that user exists. If there is no record, it creates and adds a new User.

Let's call the **SeedUser.Initialize()** method inside the ASP.NET Core Pipeline:

{% gist https://gist.github.com/bhaidar/3a2ec10b1ad35311aca90005f9054084 %}

The moment we run the application, a new user is added to the system.

**Step 4**
Now that the User Management is properly configured in our app, let's add a new migration so that all User-related tables are created in the database.

Open the **Package Manager Console** and run the following command:

```bash
Add-Migration AddUserManagement
```

The command generates the following migration:

{% gist https://gist.github.com/bhaidar/d37581fcdf8d3fb1dfd3529e3e21829e %}

Now run the following command to create all the above tables in the database:

```bash
Update-Database
```

**Step 5**
To allow the user to login and authenticate with our app, we need to add a new **AuthController** Endpoint with a single Login action for now:

{% gist https://gist.github.com/bhaidar/cc6943821b55a3dd69c7d35b6f1d865f %}

The AuthController is an ApiController with a default Endpoint route as `/api/auth`.

It requests a UserManager<ApplicationUser> instance in its constructor via Dependency Injection.

On the other hand, the **Login** action accepts as input a **LoginModel** instance. The LoginModel class is defined as follows:

```c#
public class LoginModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}
```

Inside the Login action, the code queries the database for a user by a given username. If the user doesn't exist, a proper error message is returned to the caller.

In case the user exists, the code then checks if the password matches, the one received from the HTTP Post request versus the one stored in the database. If this check fails, an Unauthorized response is generated and returned.

On the other hand if the user exists and the password matches, the code uses the **JwtSecurityToken** class to create a new token. A token usually defines a set of standard fields like the Issuer of the token, Audience, Claims (if any), Expiration Date and others.

In addition, a token is usually signed and encrypted and never sent as plain text. Therefore, the JwtSecurityToken requires that you define an instance of the **SigningCredentials** class that basically wraps a secret key (of your choice) that is used eventually to sign a token.

Finally, the Login action returns a new object containing the token, expiration date and the username associated with the token.

>To read more about JWT and understand the details, I recommend checking out this article: [JWT Introduction](https://jwt.io/introduction/)

**Step 6**
So far, the application can login a user and generate a respective JWT. However, we want to configure our app to also check and validate a JWT so that if an HTTP Request contains a header key for **Authentication** with a value in the form of **Bearer {TOKEN}**, we want the app to automatically check and validate the token and if everything is okay, to automatically login the user and mark the current HTTP Request as authenticated. 

To do so we start by registering the Authentication services in the ASP.NET Core Dependency Injection system inside the **Startup** class as follows:

{% gist https://gist.github.com/bhaidar/05ae6fe258bb614fa379d9aa8cacf8bf %}

To register the Authentication services in an ASP.NET Core Web API, you add a call to **services.AddAuthentication()** method specifying that JWT Authentication Scheme will be used.
In addition, you need to configure the ASP.NET Core Pipeline to authenticate a given request just before hitting the ASP.NET Core MVC engine:

{% gist https://gist.github.com/bhaidar/2a854ff9a33b742e768bbaa0e254d039  %}

**Step 7**
To test our work, let's open a new Postman session and try to login to the application using the single user credentials we have created so far.

Start by running the application by hitting **F5** and then open the Postman application and send the following request:

![Test JWT Backend](https://thepracticaldev.s3.amazonaws.com/i/a3d1m2bczo9ilf6pzlv2.PNG)

You send an HTTP Post request to the URL `/api/auth/login` with a request body of:

```json
{
  "username": "bhaidar",
  "password": "MySp$cialPassw0rd"
}
```

The backend API returns a valid Token together with the expiration date and the username associated with the token as follows:

```json
{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjMxMzgwMDcsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0OjQ0MzQyIiwiYXVkIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNDIifQ.OZ_0cIt1Df3Wq6TFoyJDItXJZ04vjo3jmcEQmRGiCpA",
    "expiresIn": "2019-07-14T21:00:07Z",
    "username": "bhaidar"
}
```

You can now grab this token, appended to any HTTP Request you want to be authenticated and you're done.

Finally, to protect a RESTful API Endpoint in ASP.NET Core, you simply decorate a Controller with the `[Authorize]` attribute. This attribute applies to an entire Controller or to a specific action inside a Controller.

In the next section, we add the authentication feature for the Angular app and start authenticating users before allowing them to manage movies. Stay tuned!

## Integrating Authentication in the Angular app
To start working on the Angular app, make sure you have the following tools and frameworks locally installed on your machine.

- Angular CLI v8.x [What's new in Angular CLI 8](https://blog.ninja-squad.com/2019/05/29/angular-cli-8.0/)
- Node.js 10.x [Node.js Download](https://nodejs.org/en/download)
- Visual Studio Code (or any other editor of choice) [VS Code](https://code.visualstudio.com/

In the remaining part of this section, we will go through how to integrate authentication in the Angular app and connect it to the backend Web API Auth Endpoint we just developed.

The source code for the Angular app can be found on this Github [repo](https://github.com/bhaidar/movietracker-client/tree/jwt-authentication).

**Step 1**
Create an Auth Module to hold all the services related to authenticating users in the Angular app. Run the following command in a terminal window:

```bash
ng generate module app-auth
```

This command creates a new **app-auth.module.ts** file inside the path `\src\app\app-auth`.

**Step 2**
Let's create the authentication service that handles signing in the user and managing the token state across the application.

Run the command inside a terminal window to generate a new service:

```bash
ng g service app-auth/authentication --skipTests=true
```

The above command creates a new **authentication.service.ts** file inside the path `\src\app\app-auth\`.

To login a user, we use:

{% gist https://gist.github.com/bhaidar/e60b45bb698855d92da730b6dc3b6687 %}

The **login()** method uses the HttpClient class to send a POST request to the backend Web API Endpoint `/api/auth/login` with a request payload in the body containing the username and password of the user trying to login.

Upon a successful login, the token returned from the backend API is stored inside **LocalStorage** to be used on subsequent requests to send it over as a **Bearer** authentication header.

In addition, the **currentUserSubject** of type **BehaviorSubject** is triggered with the user payload. This subject is defined as follows inside the authentication service:

{% gist https://gist.github.com/bhaidar/cd8d7859aed307e50c85c06386a9ec2c %}

The **currentUserSubject** is defined as a BehaviorSubject with an initial value equal to whatever user is stored in the LocalStorage.

Also, the **currentUser**variable is defined as an Observable on top of the **currentUserSubject**. 

Other components and services in the application can now subscribe to the **currentUser** Observable since every time a successful login operation executes, it is guaranteed that this Observable will execute with the latest user signed in as a payload.

In addition, the **currentUserValue** is defined as a public getter to retrieve the value of the **currentUserSubject** variable. Later on we will use this value inside the Auth Guard as you will see very soon.

To logout a user, we simply delete the entry from the LocalStorage and populate the **currentUserSubject** with a null value signaling to all components and services that the user has signed out of the application.

**Step 3**
To restrict access to the **MovieTrackerList** component let's rearrange the routing a little bit in our application as follows:

{% gist https://gist.github.com/bhaidar/0a02644148d786a9717a32dbcb58fdab %}

The default route now lives under `admin/movie-tracker`.

The path `/admin` now has a related component the **AppMainComponent**. This component renders an Angular Material layout for the entire application. 

In addition, any access to `/admin` is now restricted by the **AuthGuard** defined by using the **canActivate** handler that is executed before navigating to the requested route.

The `movie-tracker` route is now defined as an admin child route.

Finally, a new route is added to route requests to the **Login** component that we will build shortly.

All routing configurations have been removed from within the **MovieTracker** module and have been centralized inside the **AppModule**.

**Step 4**
Let's define the **AuthGuard** by first creating a new guard by running this command in a terminal window:

```bash
ng generate guard app-auth/auth --skipTests=true
```

The command creates a new **auth.guard.ts** file inside the path `\src\app\app-auth\`.

Paste in the following code:

{% gist  https://gist.github.com/bhaidar/c2907dca310a722f7e3a49456c7852ca %}

The **AuthGuard** implements the **CanActivate** and provides implementation for the **CanActivate** handler. 

The handle calls the **authenticationService.currentUserValue** getter to check if there is an existing user (stored in the LocalStorage). If there is one, the code returns true meaning that it is safe to allow the route navigation.

Otherwise, the user is redirected to the Login route. 

This **AuthGuard** is provided at the root of the application and hence it is accessible everywhere in the application.

**Step 5**
Let's create a new **Shared** module inside the path `\src\app\shared` to hold a couple of components that are shared across the application.

Then, you can import this module inside the **MovieTracker** module or any other module that needs to use any of the components defined in this module.

Then, let's add the **AppMainComponent* that contains HTML Markup which guarantees a standard UI layout for the entire app.

Paste in the following inside the newly created **app-main.component.ts** file:

{% gist https://gist.github.com/bhaidar/be6b8e487cd01fc86fd23fb682b5de8c %}

The component uses the Angular Material Toolbar component, to define a toolbar header for the entire application. Remember, this component is rendered for any route starting with `/admin`. 

Then, the actual route the user is navigating to, gets rendered under the `<router-outlet></router-outlet>` marker component. This guarantees a standard UI across all routes and components in the application.

The component also defines a **Logout** button so that the user can logout from the current session anytime they decide so.

**Step 6**
It's time to build the Login component. Generate a new Login component inside the **Shared** module by running this command in a terminal window:

```bash
ng g component shared/login --module=shared --skipTests=true --inlineTemplate=true --inlineStyle=true
```

Paste in the following code:

{% gist https://gist.github.com/bhaidar/805500552a7eeefa77ba94406167102a %}

The HTML markup of the Login component defines a simple form to collect the username and password from the user. It also validates the form by requiring the user to enter a username and password. In addition, it notifies the user of any errors returned from the backend Web API in case the login process fails.

This component makes use of the **ReactiveFormsModule** module from Angular. It defines the form as an object and binds it to the HTML form element.

On form submission, it calls on the **authenticationService.login** method defined above to actually login the user.

In the case a user is successfully authenticated, the code redirects the user to the home page of the application or to whatever URL the user had an intention to visit prior to being redirected to the Login route. Otherwise, if the user was not successfully authenticated, the errors returned from the backend Web API are displayed to the user.

**Step 7**
Before running the application and trying things out, two things remain pending. We need to add an HTTP Interceptor to inspect a **401 Unauthorized** response Status Code and redirect the user to the Login route accordingly. This occurs when a token is still available at the Angular app level, while in fact this token has expired on the backend Web API and the Angular app has no clue that it has expired.

Create a new **errors.interceptor.ts** file inside the **app-auth** module with the following content:

{% gist https://gist.github.com/bhaidar/5cb24f3a709be8890bd116d1d8d37d26 %}

An HTTP Interceptor is defined as a Service and provided at the root module of the application.

After a response is received from the backend server, the interceptor checks if the Status Code equals to **401**. It first logs out the user (clear the LocalStorage) and then it refreshes the entire page causing the user to be redirected to the Login route.

Finally, the service is provided in the `HTTP_INTERCEPTORS` collection.

Switch back to the **AppModule** and add this interceptor provider as follows:

```typescript
…
providers: [
    errorInterceptorProvider
  ],
…
})
export class AppModule { }
```

**Step 8**
Lastly, we need to guarantee that for each and every request sent to the backend Web API, an Authentication Bearer header is attached to the request when a user is authenticated to the application.

Let's start by adding a new **Jwt Interceptor** that inspects the request before sending it to the server. In case there is a valid user with a valid token stored locally, an Authentication Bearer header is added to the current request and its value is set to `Bearer {TOKEN}`. Where `token` is being retrieved from the LocalStorage (if any).

Create a new **jwt.interceptor.ts** file inside the **app-auth** module with the following content:

{% gist https://gist.github.com/bhaidar/c55dd4efd1061c303e874d18e2499124 %}

The interceptor above clones the current request and sets the Authentication Bearer header on the new request before sending it to the server.

Finally, the service is provided in the HTTP_INTERCEPTORS collection.

Switch back to the **AppModule** and provide this interceptor provider as follows:

```typescript
…
providers: [
    jwtInterceptorProvider,
    ...
  ],
…
})
export class AppModule { }
```

The Angular app is ready to start authenticating users. Let's give it a try.

**Step 9**
Let's run the application using the command `yarn run start`. Make sure the backend API is also running.

Once the application starts, the first thing you are redirected to is the Login route:

![Login Route](https://thepracticaldev.s3.amazonaws.com/i/ea8lvct0754c68is85sn.PNG)

Let's try an invalid combination of a username and password and see how the Login component behaves.

![Login Failed](https://thepracticaldev.s3.amazonaws.com/i/std7ypjrscdlpwy6eo3r.PNG)

Now let's try to sign in with the user credentials that we have previously seeded into the backend Web API and notice how the application now redirects us to the **Movie Tracker** route:

![Movie Tracker - Logged in](https://thepracticaldev.s3.amazonaws.com/i/r8u85xdk8771uysmkniu.PNG)

You are now redirected successfully. You can see the new UI layout and also click the **Logout** button whenever you want to sign out of the application. You may now continue managing your movies after you've signed in to the application.

##Conclusion
This second article concludes the first series of articles on Angular and the REST. The next series will cover the same stuff covered so far in the first two installments however by using a Node.js backend Web API instead of ASP.NET Core Web API and more specifically, it will use [Nest.js](https://nestjs.com/) to develop the backend Web API.


This post was written by [Bilal Haidar](https://www.bhaidar.dev/), a mentor with [This Dot](https://thisdot.co/).

*You can follow him on Twitter at [@bhaidar](https://twitter.com/bhaidar).*

*Need JavaScript consulting, mentoring, or training help? Check out our list of services at [This Dot Labs](https://thisdot.co).*