angular-8-jwt-authentication-feature-image

Angular 8 JWT Authentication with HttpInterceptor and Router

In this tutorial, we’re gonna build an Angular 8 Application (with HttpInterceptor, Router & Form Validation) that supports JWT Authentication. I will show you:

  • JWT Authentication Flow for User Signup & User Login
  • Project Structure for Angular 8 Authentication with HttpInterceptor, Router
  • How to implement HttpInterceptor
  • Creating Login, Signup Components with Form Validation
  • Angular Components for accessing protected Resources
  • How to add a dynamic Navigation Bar to Angular App
  • Working with Browser Session Storage

It sounds fantastic! Let’s explore together.

Related Posts:
In-depth Introduction to JWT-JSON Web Token

Fullstack:
Angular 8 + Spring Boot: JWT Authentication with Spring Security example
Node.js Express + Angular 8: JWT Authentication & Authorization example

Overview of Angular 8 JWT Authentication example

We will build an Angular 8 application in that:

  • There are Register, Login pages.
  • Form data will be validated by front-end before being sent to back-end.
  • Depending on User’s roles (admin, moderator, user), Navigation Bar changes its items automatically.
  • Services contain methods for sending HTTP requests & receiving reponses

Screenshots

– Signup Page:

angular-8-jwt-authentication-signup

– Login Page:

angular-8-jwt-authentication-login

– Profile Page:

angular-8-jwt-authentication-profile

– Navigation Bar for Admin account:

angular-8-jwt-authentication-admin

Demo

This is full Angular 8 JWT Authentication App (with form validation, check signup username/email duplicates, test authorization with 3 roles: Admin, Moderator, User).

In the video, we use Spring Boot for back-end REST APIs. You can find explanation and source code at:
Secure Spring Boot App with Spring Security & JWT Authentication

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

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

– 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

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 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.


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

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

If you use this front-end app for Node.js Express back-end in one of these tutorials:
Node.js + MySQL: JWT Authentication & Authorization
Node.js + MongoDB: User Authentication & Authorization with JWT

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

Conclusion

Today we’ve done so many things from setup Angular 8 Project to write Services and Components. I hope you understand the overall layers of our Angular application, and apply it in your project at ease. Now you can build a front-end app that supports JWT Authentication with Angular 8, HttpInterceptor and Router.

Happy learning, see you again!

Further Reading

Source Code

You can find the complete source code for this tutorial on Github.

57 thoughts to “Angular 8 JWT Authentication with HttpInterceptor and Router”

  1. Thanks for this excellent material, it was usefull for me and it is really clearly and easy to understand with great explanation. Great job!

  2. Remarks To: Angular 8 JWT Authentication with HttpInterceptor and Router
    It was nice to read your post. It is very organized and detailed. I did not actually implemented and run your code, (because lack of  time these days…). But I liked very much your attitude to intercept all requests (e.g. clone token to all requests) as long as there is “live” token in the memory. leaving the handle of the role-based authorizations in the server side, and save all the headache of dealing with the “whitelist / blacklist” of routs. But of course this have to be managed properly in the server code

  3. Hey! I really got to understand all the explanation and followed step by step. But I have a problem everytime I try to Log In, maybe i missed something but i don’t really get the error. I get everytime “Signup failed!
    Error: Role is not found.”

    Thanks for the code! It’s very friendly for the ones that are starting with spring+angular.

  4. Hi,
    Thanks a lot for the helpful and beautiful tutorial. i have one question, i didn’t figure out where we put our token when we send a request to get a protected ressource.
    thank you.

  5. I’m getting a CORS error from having my REST API on api.domain.com and my Angular site on dev.domain.com . How do I allow the CORS between subdomains?

    Error:

    Access to XMLHttpRequest at ‘http://api.domain.com/auth/signup’ from origin ‘http://dev.domain.com’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The ‘Access-Control-Allow-Origin’ header has a value ‘http://api.domain.com/’ that is not equal to the supplied origin.

      1. I managed to figure it out, I want to be able to accept preflight and origin from all my subdomain and main domain so I setup a multi origin configuration. Might be useful as an addition for the article. Attaching below the reference.

        https://expressjs.com/en/resources/middleware/cors.html

        var whitelist = ['http://example1.com', 'http://example2.com']
        var corsOptions = {
          origin: function (origin, callback) {
            if (whitelist.indexOf(origin) !== -1) {
              callback(null, true)
            } else {
              callback(new Error('Not allowed by CORS'))
            }
          }
        }
        
  6. Bonjour,
    j’ai obtient le problème suivant
    Access to XMLHttpRequest at ‘http://localhost:8080/api/auth/signin’ from origin ‘http://localhost:4200’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

    Malgré que j’ai ajouté au niveau de l’api rest le code suivant;@CrossOrigin(origins = “http://localhost:4200” ,allowedHeaders = “*”,allowCredentials = “true”)
    Quelqu’un peut m’aider?

    1. Hi, the server you used configures CORS for port 8081, so you have to run this Angular client with command: ng serve --port 8081 instead.

  7. Hi, I’ve tried to make some modification in the register.component.html (to add another field), but I cannot see any of them after I run “ng serve”. Do you have any idea what I am doing wrong?

      1. I just tried to display another field “check password” [I just copy/paste/change a little bit the code used for password…in html]

  8. hi, please if you explain me this:

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

    thank you

  9. Hi, when you download the project and run ng serve …
    An unhandled exception occurred: Cannot find module ‘@angular/compiler-cli’
    I have Angular 8.3.23.
    I try npm install. but nothing, an error appears
    npm WARN saveError ENOENT: no such file or directory,…….

    1. Hi, you can try these steps:
      – update angular-cli to the latest version

      $ npm remove -g angular-cli
      $ npm install -g @angular/cli@latest
      

      – update the project dependencies

      $ rm -rf node_modules dist
      $ npm install --save-dev @angular/cli@latest
      $ npm install
      
  10. This is awesome, so beautifully described, thanks a lot!

    I finished this one and I’m working on adding canActivate() method so that it protects routes of admin and user.
    If you have done any blog on it or know any sources please attach them on the reply.

    Thanks a lot, you’re a life saver.

  11. Hello, how can i assign a specific role when registering ? thank you, i try to input a role in register form but the set type doesn’t accept a string

    1. Hi, you need to transform the form data into JSON payload like this:

      {
      	"username": "user",
      	"email": "user@bezkoder.com",
      	"password": "12345678",
      	"roles": ["user", "mod"]
      }
      
  12. Hello! Thank you a lot for sharing this tutorial it is very helpful, I have a question which is I added roles to register form so I had this error :

    Signup failed!
    Invalid JSON input: Cannot deserialize instance of `java.util.HashSet` out of VALUE_STRING token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.HashSet` out of VALUE_STRING token at [Source: (PushbackInputStream); line: 1, column: 79] (through reference chain: com.suivi.app.Model.RegistrationForm[“roles”])

    Even I didn’t add roles to the form, sign up failed and if you asking about register is it working on back end yeah it works. Please can you help me to solve this issue. And Than you.

  13. thanks very much for this tutorail but i got this error with angular “error TS2306: File auth.interceptor.ts’ is not a module”

  14. Hello! I try to add role in registration but it doesn’t work

    register(user): Observable {
        return this.http.post(AUTH_API + 'signup', {
          username: user.username,
          email: user.email,
          telephone: user.telephone,
          role: user.role,
          password: user.password
        }, httpOptions);
    
  15. Hello Bezkoder,
    thanks for your wonderful guides. I followed this one and the one for node.js backend and everything works great <3 !
    Since i would call me a beginner, i have problems with the protected components. Can i send html from backend: user.controller.js , or do i need a different way to send html that works together with component.ts ?

    Thank you in advance ! Greetings from Germany

    1. Hi, if you use Node.js Express:

      var html = fs.readFileSync('./html/test.html', 'utf8')
      res.render('test', { html: html })
      

      Or you can search google with keyword: server-side rendering.

      1. Thank you very much for your help. I dont think, that server-side rendering fits my project. Any tips for protecting existing routes with the JWT provided by your tutorials without using html from the server ?

        Thank you so much for your time !

  16. Hi, thank you so much for this tutorial. I followed this one and the one for node.js backend but i got this error :

    TypeError: Cannot read property ‘_id’ of null
    at C:\Users\LDE\pfe20\backend\controllers\auth.controller.js:56:28

  17. Thank for your response.

    ****** 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 {
        return this.http.post(AUTH_API + 'signin', {
          pseudo: credentials.pseudo,
          mdp: credentials.mdp
        }, httpOptions);
      }
    
      register(user): Observable {
        return this.http.post(AUTH_API + 'signup', {
          pseudo: user.pseudo,
          email: user.email,
          mdp: user.mdp,
          nom: user.nom,
          tel: user.tel,
          cin: user.cin,
          date_embauche: user.date_embauche,
          adresse: user.adresse,
          role: user.role,
        }, httpOptions);
      }
    }
    
      1. ******auth.controller.js ******

        const config = require("../config/auth.config");
        const db = require("../models");
        const User = db.user;
        const Role = db.role;
        
        var jwt = require("jsonwebtoken");
        var bcrypt = require("bcryptjs");
        
        exports.signup = (req, res) => {
          const user = new User({
            pseudo: req.body.pseudo,
            email: req.body.email,
            mdp: bcrypt.hashSync(req.body.mdp, 8),
            nom : req.body.nom,
            tel : req.body.tel,
            cin : req.body.cin,
            date_embauche : req.body.date_embauche,
            adresse : req.body.adresse
          });
        
          user.save((err, user) => {
            if (err) {
              res.status(500).send({ message: err });
              return;
            }
        
            if (req.body.roles) {
              Role.find(
                {
                  name: { $in: req.body.roles }
                },
                (err, roles) => {
                  if (err) {
                    res.status(500).send({ message: err });
                    return;
                  }
        
                  user.roles = roles.map(role => role._id);
                  user.save(err => {
                    if (err) {
                      res.status(500).send({ message: err });
                      return;
                    }
        
                    res.send({ message: "User was registered successfully!" });
                  });
                }
              );
            } else {
              Role.findOne({ name: "client" }, (err, role) => {
                if (err) {
                  res.status(500).send({ message: err });
                  return;
                }
        
                user.roles = [role._id];
                user.save(err => {
                  if (err) {
                    res.status(500).send({ message: err });
                    return;
                  }
        
                  res.send({ message: "User was registered successfully!" });
                });
              });
            }
          });
        };
        
        ...
        
        1. Check your database, in roles collection/table. Did it have role object with name=client?
          Role.findOne({ name: "client" }...)

          If not, you should follow the step of creating 3 roles in database.

          1. Yes i have a role object with name=client but the signup form in angular only read the client role even if i put admin role in the form ? I think i have to set the payload role is an array ? how can i fix it please ?

  18. Hello, thank you for this excellent tutorial .
    i have problems with the role based authentication, the angular signup form only reads the role(admin) passed in :

     Role.findOne({ name: "admin" }, (err, role) => {
            if (err) {
              res.status(500).send({ message: err });
              return;
            }
    

    And i don’t know how to set the payload role as an array ca you help me with that please ?
    Thnak you

  19. I added a class to do CRUD, it works in the backend, when I authenticate I have the authorization to access, but in angularjs, it does not work maybe I have to add something in my code in angularjs

    1. Hi, which backend server do you use? Spring Boot or Node.js?
      You should follow the instruction for modifying app/_helpers/auth.interceptor.js.

Leave a Reply

Your email address will not be published. Required fields are marked *