Implementing Role-based Authentication with Jwt in Angular

Implementing role-based authentication in Angular applications enhances security by controlling access to different parts of the app based on user roles. JSON Web Tokens (JWT) provide a compact and secure way to transmit user information, including roles, between the client and server. This article guides you through integrating JWT with role-based access control in Angular.

Understanding JWT and Role-Based Authentication

JWTs are digitally signed tokens that contain user information, such as user ID and roles. When a user logs in, the server generates a JWT with embedded role data and sends it to the client. The client stores this token, typically in local storage, and includes it in subsequent requests to protected endpoints.

Setting Up Angular Authentication Service

To implement role-based authentication, start by creating an authentication service that manages login, token storage, and role verification. Use Angular’s HttpClient to communicate with your backend API and store the JWT securely.

Example code snippet for login:

Note: Replace your-api-endpoint with your actual API URL.

login(username: string, password: string) {
  this.http.post<any>('your-api-endpoint/login', { username, password })
    .subscribe(response => {
      localStorage.setItem('token', response.token);
    });
}

Decoding JWT and Extracting Roles

Use a JWT helper library, such as angular-jwt, to decode tokens and verify roles. This allows you to implement route guards based on user roles.

Example of role extraction:

getUserRoles(): string[] {
  const token = localStorage.getItem('token');
  if (!token) return [];
  const decodedToken = this.jwtHelper.decodeToken(token);
  return decodedToken.roles || [];
}

Implementing Role-Based Route Guards

Angular route guards can restrict access to certain routes based on roles. Create a guard that checks the user’s roles before activating a route.

Example guard implementation:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';

@Injectable({ providedIn: 'root' })
export class RoleGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    const roles = this.getUserRoles();
    const expectedRoles = route.data['roles'] as Array;

    if (roles.some(role => expectedRoles.includes(role))) {
      return true;
    } else {
      this.router.navigate(['/access-denied']);
      return false;
    }
  }

  getUserRoles(): string[] {
    const token = localStorage.getItem('token');
    if (!token) return [];
    const decodedToken = this.jwtHelper.decodeToken(token);
    return decodedToken.roles || [];
  }
}

Conclusion

Implementing role-based authentication with JWT in Angular enhances application security and user experience. By decoding tokens and setting up route guards, developers can control access efficiently based on user roles. Remember to keep your JWTs secure and validate roles on the server side for complete security.