Authentication and Authorization in Angular with JWT

Authentication & Authorization in Angular with JWT - Secure Your App | Ayodhyya

Introduction

Authentication and authorization are crucial aspects of modern web applications. They ensure that only authenticated users can access certain resources and that users have the appropriate permissions to perform actions. JSON Web Token (JWT) is a widely adopted authentication mechanism that allows secure data transmission between a client and a server. In this article, we will explore how to implement authentication and authorization in Angular using JWT.

Understanding JWT

JWT is an open standard (RFC 7519) that defines a compact, self-contained way to securely transmit information between parties as a JSON object. It is widely used for authentication because of its stateless nature and ability to carry claims. A typical JWT consists of three parts:

  1. Header – Contains metadata about the token, such as the algorithm used for signing.
  2. Payload – Contains the claims, such as user information and permissions.
  3. Signature – Ensures the integrity of the token.

A JWT looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvbiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Setting Up Angular Authentication with JWT

Step 1: Setting Up an Angular Application

First, create an Angular application using the Angular CLI:

npm install -g @angular/cli
ng new jwt-auth-app
cd jwt-auth-app

Install necessary dependencies:

npm install @auth0/angular-jwt

Step 2: Creating Authentication Service

Create an auth.service.ts file inside the services folder:

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

@Injectable({ providedIn: 'root' })
export class AuthService {
  private apiUrl = 'https://your-api-url.com/auth';

  constructor(private http: HttpClient) {}

  login(credentials: { email: string; password: string }): Observable<any> {
    return this.http.post<any>(`${this.apiUrl}/login`, credentials).pipe(
      tap(response => {
        localStorage.setItem('token', response.token);
      })
    );
  }

  logout(): void {
    localStorage.removeItem('token');
  }

  getToken(): string | null {
    return localStorage.getItem('token');
  }
}

Step 3: Implementing JWT Interceptor

Create an HTTP interceptor to attach the JWT to requests.

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
import { AuthService } from './auth.service';

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
  constructor(private authService: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const token = this.authService.getToken();
    if (token) {
      req = req.clone({
        setHeaders: { Authorization: `Bearer ${token}` }
      });
    }
    return next.handle(req);
  }
}

Add the interceptor to the Angular providers in app.module.ts:

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { JwtInterceptor } from './services/jwt-interceptor';

providers: [
  { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }
]

Step 4: Protecting Routes with Route Guards

To protect specific routes, use Angular route guards.

Create auth.guard.ts:

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(): boolean {
    if (this.authService.getToken()) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}

Apply the guard to protected routes:

const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }
];

Step 5: Implementing Role-Based Authorization

Modify the authentication service to extract roles:

import jwtDecode from 'jwt-decode';

getUserRole(): string | null {
  const token = this.getToken();
  if (token) {
    const decodedToken: any = jwtDecode(token);
    return decodedToken.role;
  }
  return null;
}

Create an admin.guard.ts for role-based access:

@Injectable({ providedIn: 'root' })
export class AdminGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(): boolean {
    if (this.authService.getUserRole() === 'admin') {
      return true;
    } else {
      this.router.navigate(['/forbidden']);
      return false;
    }
  }
}

Use AdminGuard for admin routes:

const routes: Routes = [
  { path: 'admin', component: AdminComponent, canActivate: [AdminGuard] }
];

Conclusion

Implementing JWT-based authentication in Angular improves security and scalability by providing a stateless authentication mechanism. This approach enables secure authentication, role-based access control, and protection against common security threats. By following best practices such as using route guards and interceptors, developers can ensure a robust authentication system in their Angular applications.

Sandip Mhaske

I’m a software developer exploring the depths of .NET, AWS, Angular, React, and digital entrepreneurship. Here, I decode complex problems, share insightful solutions, and navigate the evolving landscape of tech and finance.

Post a Comment

Previous Post Next Post