Angular 9 Authentication Using JWT

Angular 9 Authentication Using JWT

Share

Loading

The MEAN stack is MongoDB, Express.js, AngularJS (or Angular), and Node.js. It’s an open-source and free available JavaScript software stack for building dynamic web sites and web applications. In MEAN Stack, all components support programs that are written in JavaScript, MEAN applications can be written in one language for both server-side and client-side execution environments.

Before starting to learn Authentication with JWT and MEAN, hope you have an idea about MEAN setup.

So let’s start with creating angular authentication components then we move to setup node authentication and JWT access token step by step.

I refer Angular 9 Mean Stack artical to setup MEAN stack ,you can use as per your need.

There are many articles available online for setting up Mongo authentication with JWT. From them I place one of the simple and clean article which you may refer: Mongo authentication with JWT.

The steps will start from the Angular 9 app from where users client agent will send the API implemetning the JWT authentication endpoints to the the Node/Express auth endpoint generates JWT tokens upon registration or login, and send them back to the Angular 9 app.

Our Angular app uses local storage to persist the JWT token, verifies the JWT tokens when rendering protected views and sends the JWT token back to Node auth server when accessing protected API routes/resources.

Login, Register and Profile pages are part of our angular app authentication process. Use below commands to create these components:

$ ng generate component login
$ ng generate component register
$ ng generate component user-profile

Open the src/app/app-routing.module.ts file and import the components then add them to routes array like:

const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'profile/:id', component: UserProfileComponent }
];

Create and expose below APIs from your node server:

POST /users/login
POST /users/register
GET /users/profile/id
PUT /users/update/id
DELETE /users/delete/id

Now, let’s set up the HttpClient request on an angular app passed through Authentication Service only.

HttpClient

Open the src/app/app.module.ts file, import HttpClientModule and add it the imports array as follows:

import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule
]
});

Authentication Service

Here, we need to create the User model inside a src/app/user.ts file as follows:

export class User {
_id: String;
name: String;
email: String;
password: String;
}

Next, head back to your command-line interface and run the following command:

$ ng generate service auth

Next, open the generated src/app/auth.service.ts file and update it as follows:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { User } from './user';

@Injectable({
providedIn: 'root'
})

export class AuthService {
API_URL: string = 'http://localhost:4000';
headers = new HttpHeaders().set('Content-Type', 'application/json');
currentUser = {};
constructor(private httpClient: HttpClient,public router: Router){}

//Function to create a user record
register(user: User): Observable {
return this.httpClient.post(${this.API_URL}/users/register, user).pipe(catchError(this.handleError)
)
}

//Function to get JWT access token that we will use to allow the user to access the protected resources on the server
login(user: User) {
return this.httpClient.post(${this.API_URL}/users/login, user)
.subscribe((res: any) => {
localStorage.setItem('access_token', res.token)
this.getUserProfile(res._id).subscribe((res) => {
this.currentUser = res;
this.router.navigate(['users/profile/' + res.msg._id]);
})
})
}

//Function to access the token stored in the local storage
getAccessToken() {
return localStorage.getItem('access_token');
}

// Function to check user is logged in OR not
get isLoggedIn(): boolean {
let authToken = localStorage.getItem('access_token');
return (authToken !== null) ? true : false;
}

//Function to logout user, remove the access token from local storage and redirects the user to login page
logout() {
if (localStorage.removeItem('access_token') == null) {
this.router.navigate(['users/login']);
} }

//Function to retrieve the user profile
getUserProfile(id): Observable {
return this.httpClient.get(${this.API_URL}/users/profile/${id}, { headers: this.headers }).pipe(
map((res: Response) => {
return res || {}
}),
catchError(this.handleError)
)
}

// Function to handle any errors
handleError(error: HttpErrorResponse) {
let msg = '';
if (error.error instanceof ErrorEvent) {
// client-side error
msg = error.error.message;
} else {
// server-side error
msg = Error Code: ${error.status}\nMessage: ${error.message};
}
return throwError(msg);
}
}

So, this is what We first import the necessary APIs like Router, HttpClient, HttpHeaders, HttpErrorResponse, Observable, throwError, catchError, map and the User class.

And then we inject a HttpClient via the service via constructor and we define the API_URL, headers and currentUser variables.

Now, create and set up an auth guard which will be used to protect the users/profile/ route from non logged in users.

Open command-line interface and run the following command:

$ generate guard auth

Now, open the src/app/auth.guard.ts file and add the following code:

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot,
UrlTree, CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
public authService: AuthService,
public router: Router
) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable | Promise | boolean {
if (this.authService.isLoggedIn() !== true) {
window.alert("Access not allowed!");
this.router.navigate(['users/login'])
}
return true;
}
}

Open the src/app/app-routing.module.ts file and import the authentication guard and apply it to the route as follows:

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

import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { UserProfileComponent } from './user-profile/user-profile.component';

import { AuthGuard } from "./auth.guard";

const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'profile/:id', component: UserProfileComponent, canActivate: [AuthGuard] }
];

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

export class AppRoutingModule { }

Now, we have each thing ready to test using postman OR any other api tool. But here we still have angular form setup. So finally we set up the reactive form for Register/Login/Profile.

To import reactive form module, Open the src/app/app.module.ts
file and import both ReactiveFormsModule and FormsModule then add them to the imports array:

import { ReactiveFormsModule, FormsModule } from '@angular/forms';

@NgModule({
imports: [
ReactiveFormsModule,
FormsModule
],
})

export class AppModule { }

To create the registration and login forms to our components, Open the src/app/register.component.ts file and add the following code:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from "@angular/forms";
import { AuthService } from './auth.service';
import { Router } from '@angular/router';

@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})

export class RegisterComponent implements OnInit {
registerForm: FormGroup;
constructor(
public formBuilder: FormBuilder,
public authService: AuthService,
public router: Router
) {
this.registerForm= this.formBuilder.group({
name: [''],
email: [''],
password: ['']
})
}
ngOnInit() { }
registerUser() {
this.authService.register(this.registerForm.value).subscribe((res) => {
if (res.result) {
this.registerForm.reset()
this.router.navigate(['login']);
}
})
}
}

To set template part, open the src/app/register.component.html file and add the following code:

Register

Register

Likewise, add the login form. Open the src/app/login.component.ts file and update it as follows:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup } from "@angular/forms";
import { AuthService } from './auth.service';

@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginForm: FormGroup;
constructor(
public formBuilder: FormBuilder,
public authService: AuthService,
public router: Router
) {
this.loginForm= this.formBuilder.group({
email: [''],
password: ['']
})
}
ngOnInit() { }
loginUser() {
this.authService.login(this.loginForm.value)
}
}

To setup login form template, open the src/app/login.component.html file and add the following code:

Login

In last, for profile page form, Open the src/app/user-profile/user-profile.component.ts file and add the following code:

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

@Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.css']
})

export class UserProfileComponent implements OnInit {
currentUser: Object = {};
constructor(
public authService: AuthService,
private activatedRoute: ActivatedRoute
) {
let id = this.activatedRoute.snapshot.paramMap.get('id');
this.authService.getUserProfile(id).subscribe(res => {
this.currentUser = res.msg;
})
}
ngOnInit() { }
}

To set up profile page data, open the src/app/user-profile/user-profile.component.html file and add the following code:

Your User Information

Name:

Email:

Before we test Register, Login, Profile feature let’s add logout button to hide/show nav items in our MEAN stack user authentication app:

Open the src/app/app.component.ts file, import and inject AuthService and add the logout () method as follows:

import { Component } from '@angular/core';
import { AuthService } from './auth.service';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {

constructor(public authService: AuthService) { }
logout() {
this.authService.logout()
}
}

Next, open the src/app/app.component.html file and add update it as follows:


Conclusion

In this article, we have seen by code examples how we can implement the flow of user authentication using APIs and JWT tokens in a MEAN stack web application. Further we have looked that how to create the frontend forms and handler service using Angular 9.

Back to Top