In this article, we are going to continue where we left off in our Angular 10 Authentication and Authorization using JWT. If you haven’t gone through my recent article, you might want to follow it.
- Angular JWT Authentication and Authorization preparing frontend.
- Setup backend ready for JWT authentication and pass it to the frontend.
If you already have JWT setup on your other backend services and tested its API through postman to obtain a valid token after sending the valid credentials you can follow this guide. Else you can visit the previous tutorial create a service to pass you a valid JWT token.
Lets, head back to angular and get started.
Last time we have left of creating a loginCheck()
function in our login.component.ts
Now it is time to use it to make some changes to functions.
There are two things that happen while validating, either you will get SUCCESS or ERROR response. If it is a SUCCESS we have to save it in our local store and validate it. If its an ERROR we will throw an ERROR message that login failed.
If Success Response
Let’s try to login from the frontend then. Get your project started and try to log in. I hope your backend server is running by now and accepting frontend requests.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public loginCheck() { // console.log('login called'); this.httpClient.post('http://localhost:8000/api/auth/login', this.loginFormData) .subscribe( successResponse => this.processTokenResponse(successResponse), errorRespose => this.handleError(errorRespose) ); } private handleError(errorResponse) { console.log(errorResponse); return null; } |
If your login is successfully validated then, the next is:-
- Add a function to save token into local storage.
- Remove token function for logging out.
- Validate token in order to validate that, the generated token is a valid token.
So we are going to all these authentication-related functions inside our token.service.ts
so that we can inject it wherever we want and use it.
Here we will process the token and then we will redirect the user to the HomeComponent that we created at the beginning of this series. Now, create a new function called processTokenResponse();
and add these codes.
1 2 3 4 5 |
private processTokenResponse(response) { this.tokenService.processToken(response.access_token); this.tokenService.changeLoggedInStatus(true); this.router.navigateByUrl('/'); } |
Now we have to create some function to save and validate our token. It might be confusing if I tried to explain each and everything the function we could go through. So here is the full token.service.ts file. I have placed comments so that it would be easier for you to understand.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { Router } from '@angular/router'; import { HttpClient, HttpEvent, HttpUserEvent } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class TokenService { private iss: { loginUrl: string, signupUrl: string } = { loginUrl: 'http://localhost:8000/api/auth/login', signupUrl: 'http://localhost:8000/api/auth/signup' } public loggedIn = new BehaviorSubject<boolean>(this.isLoggedIn()); public loggedInStatus = this.loggedIn.asObservable(); constructor(private readonly router: Router, private httpClient: HttpClient) { } public processToken(accessToken): void { this.setToken(accessToken); } changeLoggedInStatus(booleanData: boolean) { this.loggedIn.next(booleanData); } private setToken(accessToken): void { // set token to localstrage localStorage.setItem('token', accessToken); } public getToken(): string { // Retrieve token from local storage return localStorage.getItem('token'); } public removeToken(): void { // Remove token from local storage. We will use this in cse of logout localStorage.removeItem('token'); } private validateToken(): boolean { // Validate where token sent is a valid token and not a modified token const token = this.getToken(); let isValidToken = false; if (token != null) { const tokenPiece = this.processPayload(token); isValidToken = Object.values(this.iss).indexOf(tokenPiece.iss) > -1 ? true : false; } return isValidToken; } private processPayload(accessToken) { const payload = accessToken.split('.')[1]; return JSON.parse(atob(payload)); } public isLoggedIn(): boolean { // Check whether the user is loggedin or not return this.validateToken(); } public logout() { // Once logout button is pressed change the login status to false and redirect user to login page. this.changeLoggedInStatus(false); this.removeToken(); this.router.navigateByUrl('/login'); } } |
So, finally, If you have followed every step till now, you will have a fully functional authentication system ready. If you are confused you can check the link to my GitHub Repo. Now, let’s handle the authorization part.
Creating Authorization Guards to Prevent Access to the Pages.
Since we have logged in now we don’t want users to get access to the login page. So what we will do is redirect them to HomeComponent if they tried to visit the login page also, we have to prevent the user to access to the homepage if they are not logged in. To do this we need to create two Authorization Guards.
So, create auth.guard.ts
in the place where your app.component.html
resides and copy these codes below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import { Injectable } from "@angular/core"; import { CanActivate, ActivatedRoute, RouterStateSnapshot, ActivatedRouteSnapshot, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { TokenService } from './login/token.service'; @Injectable() export class AuthorizationGuard implements CanActivate { constructor(private tokenService: TokenService, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { if (this.tokenService.isLoggedIn()) { return true; } else { this.router.navigateByUrl('/login'); } return false; } } @Injectable() export class UnAuthorizationGuard implements CanActivate { constructor(private tokenService: TokenService, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { if (!this.tokenService.isLoggedIn()) { return true; } else { this.router.navigateByUrl('/'); } return false; } } |
Now, we need to register these guards in app.module.ts
in order to use it. Head over to it and add these lines inside providers.
1 2 |
AuthorizationGuard, UnAuthorizationGuard, |
Now use these guards inside app-routing.module.ts
in routes by using canActivate
. Now your routes should be looking something like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { LoginComponent } from './login/login.component'; import { HomeComponent } from './home/home.component'; import { AuthorizationGuard, UnAuthorizationGuard } from './auth.guard'; const routes: Routes = [ { path: '', component: HomeComponent, canActivate: [AuthorizationGuard] }, { path: 'login', component: LoginComponent, canActivate: [UnAuthorizationGuard] }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } |
We use UnAuthorizedGuard to page where we want to give them access then they are not logged in. If they are logged in we will use an AuthorizationGuard to prevent access unless logged in.
Finally, it is done. Fully functional token-based authentication and authorization in angular 10. One more thing remaining is that we need to show the login link in the navbar and logout link if it is logged in. So head over to app.component.ts and add these lines.
1 2 3 4 5 6 7 8 9 10 11 12 |
public isLoggedIn: boolean; constructor(private tokenService: TokenService, private router: Router) { } ngOnInit() { this.tokenService.loggedInStatus.subscribe(item => this.isLoggedIn = item); } signOut($event: MouseEvent) { $event.preventDefault(); this.tokenService.logout(); } |
Now use isLoggedIn in the navbar inside <li>
like below.
1 2 |
<li class="nav-item"><a class="nav-link" routerLink="/login" *ngIf="!isLoggedIn">Login</a></li> <li class="nav-item"><a class="nav-link" *ngIf="isLoggedIn" (click)="signOut($event)">Logout</a></li> |
So this is it. If you have any problem regarding following this tutorial you can download this GitHub project from my repo.
Leave a Reply