# Angular 8 JWT Authentication with HttpInterceptor and Router

### Flow for User Registration and User Login

For JWT Authentication, we’re gonna call 2 endpoints:

* POST `api/auth/signup` for User Registration
* POST `api/auth/signin` for User Login

You can take a look at following flow to have an overview of Requests and Responses that Angular 8 Client will make or receive.

![angular-8-jwt-authentication-flow](https://bezkoder.com/wp-content/uploads/2020/01/angular-8-jwt-authentication-flow.png)

Angular Client must add a JWT to HTTP Authorization Header before sending request to protected resources. This can be done by using `HttpInterceptor`.

### Angular App Diagram with Router and HttpInterceptor

Now look at the diagram below.

![angular-8-jwt-authentication-overview](https://bezkoder.com/wp-content/uploads/2020/01/angular-8-jwt-authentication-overview.png)

– The `App` component is a container using `Router`. It gets user token & user information from _Browser Session Storage_ via `token-storage.service`. Then the navbar now can display based on the user login state & roles.

– `Login` & `Register` components have form for submission data (with support of _Form Validation_). They use `token-storage.service` for checking state and `auth.service` for sending signin/signup requests.

– `auth.service` uses Angular HttpClient (`$http` service) to make authentication requests.\
– every HTTP request by `$http` service will be inspected and transformed before being sent by `auth-interceptor`.

– `Home` component is public for all visitor.

– `Profile` component get `user` data from _Session Storage_.

– `BoardUser`, `BoardModerator`, `BoardAdmin` components will be displayed depending on `roles` from _Session Storage_. In these components, we use `user.service` to get protected resources from API.

### Technology

– Angular 8\
– RxJS 6

### Setup Angular 8 Project

Let’s open cmd and use Angular CLI to create a new Angular Project as following command:

```
ng new Angular8JwtAuth
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
```

We also need to generate some Components and Services:

```
ng g s _services/auth
ng g s _services/token-storage
ng g s _services/user

ng g c login
ng g c register
ng g c home
ng g c profile
ng g c board-admin
ng g c board-moderator
ng g c board-user
```

After the previous process is done, under **src** folder, let’s create **\_helpers** folder and _auth.interceptor.ts_ file inside.

Now you can see that our project directory structure looks like this.

### Project Structure

![angular-8-jwt-authentication-project-structure](https://bezkoder.com/wp-content/uploads/2020/01/angular-8-jwt-authentication-project-structure.png)

### Setup App Module

Open _app.module.ts_, then import `FormsModule` & `HttpClientModule`.\
We also need to add `authInterceptorProviders` in `providers`. I will show you how to define it later on this tutorial.

```
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { HomeComponent } from './home/home.component';
import { BoardAdminComponent } from './board-admin/board-admin.component';
import { BoardUserComponent } from './board-user/board-user.component';
import { BoardModeratorComponent } from './board-moderator/board-moderator.component';
import { ProfileComponent } from './profile/profile.component';

import { authInterceptorProviders } from './_helpers/auth.interceptor';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    RegisterComponent,
    HomeComponent,
    BoardAdminComponent,
    BoardUserComponent,
    BoardModeratorComponent,
    ProfileComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [authInterceptorProviders],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

### Create Services

#### Authentication Service

This service sends signup, login HTTP POST requests to back-end.

**\_services**/_auth.service.ts_

```
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

const AUTH_API = 'http://localhost:8080/api/auth/';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(private http: HttpClient) { }

  login(credentials): Observable<any> {
    return this.http.post(AUTH_API + 'signin', {
      username: credentials.username,
      password: credentials.password
    }, httpOptions);
  }

  register(user): Observable<any> {
    return this.http.post(AUTH_API + 'signup', {
      username: user.username,
      email: user.email,
      password: user.password
    }, httpOptions);
  }
}
```

#### Token Storage Service

`TokenStorageService` to manages token and user information (username, email, roles) inside Browser’s Session Storage. For Logout, we only need to clear this Session Storage.

**\_services**/_token-storage.service.ts_

```
import { Injectable } from '@angular/core';

const TOKEN_KEY = 'auth-token';
const USER_KEY = 'auth-user';

@Injectable({
  providedIn: 'root'
})
export class TokenStorageService {

  constructor() { }

  signOut() {
    window.sessionStorage.clear();
  }

  public saveToken(token: string) {
    window.sessionStorage.removeItem(TOKEN_KEY);
    window.sessionStorage.setItem(TOKEN_KEY, token);
  }

  public getToken(): string {
    return sessionStorage.getItem(TOKEN_KEY);
  }

  public saveUser(user) {
    window.sessionStorage.removeItem(USER_KEY);
    window.sessionStorage.setItem(USER_KEY, JSON.stringify(user));
  }

  public getUser() {
    return JSON.parse(sessionStorage.getItem(USER_KEY));
  }
}
```

#### Data Service

This service provides methods to access public and protected resources.

**\_services**/_user.service.ts_

```
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

const API_URL = 'http://localhost:8080/api/test/';

@Injectable({
  providedIn: 'root'
})
export class UserService {

  constructor(private http: HttpClient) { }

  getPublicContent(): Observable<any> {
    return this.http.get(API_URL + 'all', { responseType: 'text' });
  }

  getUserBoard(): Observable<any> {
    return this.http.get(API_URL + 'user', { responseType: 'text' });
  }

  getModeratorBoard(): Observable<any> {
    return this.http.get(API_URL + 'mod', { responseType: 'text' });
  }

  getAdminBoard(): Observable<any> {
    return this.http.get(API_URL + 'admin', { responseType: 'text' });
  }
}
```

You can see that it’s simple because we have `HttpInterceptor`.

### Http Interceptor

[HttpInterceptor](https://angular.io/api/common/http/HttpInterceptor) has `intercept()` method to inspect and transform HTTP requests before they are sent to server.

`AuthInterceptor` implements `HttpInterceptor`. We’re gonna add **Authorization** header with _‘Bearer’_ prefix to the token.

**\_helpers**/_auth.interceptor.ts_

```
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';

import { TokenStorageService } from '../_services/token-storage.service';

const TOKEN_HEADER_KEY = 'Authorization';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private token: TokenStorageService) { }

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    let authReq = req;
    const token = this.token.getToken();
    if (token != null) {
      authReq = req.clone({ headers: req.headers.set(TOKEN_HEADER_KEY, 'Bearer ' + token) });
    }
    return next.handle(authReq);
  }
}

export const authInterceptorProviders = [
  { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
];
```

`intercept()` gets `HTTPRequest` object, change it and forward to `HttpHandler` object’s `handle()` method. It transforms `HTTPRequest` object into an `Observable<HttpEvents>`.

`next: HttpHandler object` represents the next interceptor in the chain of interceptors. The final ‘next’ in the chain is the Angular [HttpClient](https://angular.io/guide/http).

**Note:** For Node.js Express back-end, please use **x-access-token** header like this:

```
...
const TOKEN_HEADER_KEY = 'x-access-token';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  ...
  intercept(req: HttpRequest, next: HttpHandler) {
    ...
    if (token != null) {
      authReq = req.clone({ headers: req.headers.set(TOKEN_HEADER_KEY, token) });
    }
    return next.handle(authReq);
  }
}
...
```

### Add Bootstrap to Angular project

Open _index.html_ and import Bootstrap inside `<head />` tag.

```
<!DOCTYPE html>
<html lang="en">
  <head>
    ...
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
      integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <app-root></app-root>
  </body>
</html>
```

### Create Components for Authentication

#### Register Component

This component binds form data (`username`, `email`, `password`) from template to `AuthService.register()` method that returns an `Observable` object.

**register**/_register.component.ts_

```
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../_services/auth.service';

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
  form: any = {};
  isSuccessful = false;
  isSignUpFailed = false;
  errorMessage = '';

  constructor(private authService: AuthService) { }

  ngOnInit() {
  }

  onSubmit() {
    this.authService.register(this.form).subscribe(
      data => {
        console.log(data);
        this.isSuccessful = true;
        this.isSignUpFailed = false;
      },
      err => {
        this.errorMessage = err.error.message;
        this.isSignUpFailed = true;
      }
    );
  }
}
```

We use Form Validation in the template:

* `username`: required, minLength=3, maxLength=20
* `email`: required, email format
* password: required, minLength=6

**register**/_register.component.html_

```
<div class="col-md-12">
  <div class="card card-container">
    <img
      id="profile-img"
      src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
      class="profile-img-card"
    />
    <form
      *ngIf="!isSuccessful"
      name="form"
      (ngSubmit)="f.form.valid && onSubmit()"
      #f="ngForm"
      novalidate
    >
      <div class="form-group">
        <label for="username">Username</label>
        <input
          type="text"
          class="form-control"
          name="username"
          [(ngModel)]="form.username"
          required
          minlength="3"
          maxlength="20"
          #username="ngModel"
        />
        <div class="alert-danger" *ngIf="f.submitted && username.invalid">
          <div *ngIf="username.errors.required">Username is required</div>
          <div *ngIf="username.errors.minlength">
            Username must be at least 3 characters
          </div>
          <div *ngIf="username.errors.maxlength">
            Username must be at most 20 characters
          </div>
        </div>
      </div>
      <div class="form-group">
        <label for="email">Email</label>
        <input
          type="email"
          class="form-control"
          name="email"
          [(ngModel)]="form.email"
          required
          email
          #email="ngModel"
        />
        <div class="alert-danger" *ngIf="f.submitted && email.invalid">
          <div *ngIf="email.errors.required">Email is required</div>
          <div *ngIf="email.errors.email">
            Email must be a valid email address
          </div>
        </div>
      </div>
      <div class="form-group">
        <label for="password">Password</label>
        <input
          type="password"
          class="form-control"
          name="password"
          [(ngModel)]="form.password"
          required
          minlength="6"
          #password="ngModel"
        />
        <div class="alert-danger" *ngIf="f.submitted && password.invalid">
          <div *ngIf="password.errors.required">Password is required</div>
          <div *ngIf="password.errors.minlength">
            Password must be at least 6 characters
          </div>
        </div>
      </div>
      <div class="form-group">
        <button class="btn btn-primary btn-block">Sign Up</button>
      </div>

      <div class="alert alert-warning" *ngIf="f.submitted && isSignUpFailed">
        Signup failed!<br />{{ errorMessage }}
      </div>
    </form>

    <div class="alert alert-success" *ngIf="isSuccessful">
      Your registration is successful!
    </div>
  </div>
</div>
```

#### Login Component

Login Component also uses `AuthService` to work with `Observable` object. Besides that, it calls `TokenStorageService` methods to check loggedIn status and save Token, User info to Session Storage.

**login**/_login.component.ts_

```
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../_services/auth.service';
import { TokenStorageService } from '../_services/token-storage.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  form: any = {};
  isLoggedIn = false;
  isLoginFailed = false;
  errorMessage = '';
  roles: string[] = [];

  constructor(private authService: AuthService, private tokenStorage: TokenStorageService) { }

  ngOnInit() {
    if (this.tokenStorage.getToken()) {
      this.isLoggedIn = true;
      this.roles = this.tokenStorage.getUser().roles;
    }
  }

  onSubmit() {
    this.authService.login(this.form).subscribe(
      data => {
        this.tokenStorage.saveToken(data.accessToken);
        this.tokenStorage.saveUser(data);

        this.isLoginFailed = false;
        this.isLoggedIn = true;
        this.roles = this.tokenStorage.getUser().roles;
        this.reloadPage();
      },
      err => {
        this.errorMessage = err.error.message;
        this.isLoginFailed = true;
      }
    );
  }

  reloadPage() {
    window.location.reload();
  }
}
```

Here are what we validate in the form:

* `username`: required
* password: required, minLength=6

**login**/_login.component.html_

```
<div class="col-md-12">
  <div class="card card-container">
    <img
      id="profile-img"
      src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
      class="profile-img-card"
    />
    <form
      *ngIf="!isLoggedIn"
      name="form"
      (ngSubmit)="f.form.valid && onSubmit()"
      #f="ngForm"
      novalidate
    >
      <div class="form-group">
        <label for="username">Username</label>
        <input
          type="text"
          class="form-control"
          name="username"
          [(ngModel)]="form.username"
          required
          #username="ngModel"
        />
        <div
          class="alert alert-danger"
          role="alert"
          *ngIf="f.submitted && username.invalid"
        >
          Username is required!
        </div>
      </div>
      <div class="form-group">
        <label for="password">Password</label>
        <input
          type="password"
          class="form-control"
          name="password"
          [(ngModel)]="form.password"
          required
          minlength="6"
          #password="ngModel"
        />
        <div
          class="alert alert-danger"
          role="alert"
          *ngIf="f.submitted && password.invalid"
        >
          <div *ngIf="password.errors.required">Password is required</div>
          <div *ngIf="password.errors.minlength">
            Password must be at least 6 characters
          </div>
        </div>
      </div>
      <div class="form-group">
        <button class="btn btn-primary btn-block">
          Login
        </button>
      </div>
      <div class="form-group">
        <div
          class="alert alert-danger"
          role="alert"
          *ngIf="f.submitted && isLoginFailed"
        >
          Login failed: {{ errorMessage }}
        </div>
      </div>
    </form>

    <div class="alert alert-success" *ngIf="isLoggedIn">
      Logged in as {{ roles }}.
    </div>
  </div>
</div>
```

### Create Role-based Components

#### Public Component

Our Home Component will use `UserService` to get public resources from back-end.

**home**/_home.component.ts_

```
import { Component, OnInit } from '@angular/core';
import { UserService } from '../_services/user.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
  content: string;

  constructor(private userService: UserService) { }

  ngOnInit() {
    this.userService.getPublicContent().subscribe(
      data => {
        this.content = data;
      },
      err => {
        this.content = JSON.parse(err.error).message;
      }
    );
  }
}
```

**home**/_home.component.html_

```
<div class="container">
  <header class="jumbotron">
    <p>{{ content }}</p>
  </header>
</div>
```

#### Protected Components

These Components are role-based. But authorization will be processed by back-end.\
We only need to call `UserService` methods:

* getUserBoard()
* getModeratorBoard()
* getAdminBoard()

Here is an example for `BoardAdminComponent`.\
`BoardModeratorComponent` & `BoardUserComponent` are similar.

**board-admin**/_board-admin.component.ts_

```javascript
import { Component, OnInit } from '@angular/core';
import { UserService } from '../_services/user.service';

@Component({
  selector: 'app-board-admin',
  templateUrl: './board-admin.component.html',
  styleUrls: ['./board-admin.component.css']
})
export class BoardAdminComponent implements OnInit {
  content = '';

  constructor(private userService: UserService) { }

  ngOnInit() {
    this.userService.getAdminBoard().subscribe(
      data => {
        this.content = data;
      },
      err => {
        this.content = JSON.parse(err.error).message;
      }
    );
  }
}
```

**board-admin**/_board-admin.component.html_

```
<div class="container">
  <header class="jumbotron">
    <p>{{ content }}</p>
  </header>
</div>
```

### App Routing Module

We configure the Routing for our Angular app in _app-routing.module.ts_.

```
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { RegisterComponent } from './register/register.component';
import { LoginComponent } from './login/login.component';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { BoardUserComponent } from './board-user/board-user.component';
import { BoardModeratorComponent } from './board-moderator/board-moderator.component';
import { BoardAdminComponent } from './board-admin/board-admin.component';

const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
  { path: 'profile', component: ProfileComponent },
  { path: 'user', component: BoardUserComponent },
  { path: 'mod', component: BoardModeratorComponent },
  { path: 'admin', component: BoardAdminComponent },
  { path: '', redirectTo: 'home', pathMatch: 'full' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```

`Routes` array is passed to the `RouterModule.forRoot()` method.\
We’re gonna use `<router-outlet></router-outlet>` directive in the App Component where contains navbar and display Components (corresponding to routes) content.

### App Component

This component is the root Component of our Angular application, it defines the root tag: `<app-root></app-root>` that we use in _index.html_.

/_.component.ts_

```
import { Component, OnInit } from '@angular/core';
import { TokenStorageService } from './_services/token-storage.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  private roles: string[];
  isLoggedIn = false;
  showAdminBoard = false;
  showModeratorBoard = false;
  username: string;

  constructor(private tokenStorageService: TokenStorageService) { }

  ngOnInit() {
    this.isLoggedIn = !!this.tokenStorageService.getToken();

    if (this.isLoggedIn) {
      const user = this.tokenStorageService.getUser();
      this.roles = user.roles;

      this.showAdminBoard = this.roles.includes('ROLE_ADMIN');
      this.showModeratorBoard = this.roles.includes('ROLE_MODERATOR');

      this.username = user.username;
    }
  }

  logout() {
    this.tokenStorageService.signOut();
    window.location.reload();
  }
}
```

First, we check `isLoggedIn` status using `TokenStorageService`, if it is `true`, we get user’s roles and set value for `showAdminBoard` & `showModeratorBoard` flag. They will control how template navbar displays its items.

The App Component template also has a **Logout** button link that call `logout()` method and reload the window.

_app.component.html_

```
<div id="app">
  <nav class="navbar navbar-expand navbar-dark bg-dark">
    <a href="#" class="navbar-brand">bezKoder</a>
    <ul class="navbar-nav mr-auto" routerLinkActive="active">
      <li class="nav-item">
        <a href="/home" class="nav-link" routerLink="home">Home </a>
      </li>
      <li class="nav-item" *ngIf="showAdminBoard">
        <a href="/admin" class="nav-link" routerLink="admin">Admin Board</a>
      </li>
      <li class="nav-item" *ngIf="showModeratorBoard">
        <a href="/mod" class="nav-link" routerLink="mod">Moderator Board</a>
      </li>
      <li class="nav-item">
        <a href="/user" class="nav-link" *ngIf="isLoggedIn" routerLink="user">User</a>
      </li>
    </ul>

    <ul class="navbar-nav ml-auto" *ngIf="!isLoggedIn">
      <li class="nav-item">
        <a href="/register" class="nav-link" routerLink="register">Sign Up</a>
      </li>
      <li class="nav-item">
        <a href="/login" class="nav-link" routerLink="login">Login</a>
      </li>
    </ul>

    <ul class="navbar-nav ml-auto" *ngIf="isLoggedIn">
      <li class="nav-item">
        <a href="/profile" class="nav-link" routerLink="profile">{{ username }}</a>
      </li>
      <li class="nav-item">
        <a href class="nav-link" (click)="logout()">LogOut</a>
      </li>
    </ul>
  </nav>

  <div class="container">
    <router-outlet></router-outlet>
  </div>
</div>
```

### Run the Angular App

You can run this App with command: `ng serve`.

This client will work well with the back-end in the post:\
[Spring Boot, MongoDB: JWT Authentication with Spring Security](https://bezkoder.com/spring-boot-jwt-auth-mongodb/)

If you use this front-end app for Node.js Express back-end in one of these tutorials:\
– [Node.js + MySQL: JWT Authentication & Authorization](https://bezkoder.com/node-js-jwt-authentication-mysql/)\
– [Node.js + MongoDB: User Authentication & Authorization with JWT](https://bezkoder.com/node-js-mongodb-auth-jwt/)

It configures CORS for port **8081**, so you have to run command: `ng serve --port 8081` instead.

###
