Angular Functions

 

Angular and Authentication with JWT: Securing User Data

In modern web applications, secure authentication is paramount. JSON Web Tokens (JWT) have become a standard for securely transmitting information between parties as a JSON object. They are compact, self-contained, and can be easily used for authentication and information exchange. This article explores how to implement JWT-based authentication in Angular, ensuring secure user data handling and robust session management.

Angular and Authentication with JWT: Securing User Data

 Understanding JWT

JWT is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

 Implementing JWT in Angular

Angular provides various libraries and tools to implement JWT authentication. Here’s a step-by-step guide to integrating JWT-based authentication in an Angular application.

 1. Setting Up the Angular Project

Before diving into JWT, ensure that you have an Angular project set up. You can create a new Angular project using the Angular CLI.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```bash
ng new angular-jwt-auth
cd angular-jwt-auth
```
```bash ng new angular-jwt-auth cd angular-jwt-auth ```
```bash
ng new angular-jwt-auth
cd angular-jwt-auth
```

Install the necessary packages:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```bash
npm install @auth0/angular-jwt
npm install --save angular-oauth2-oidc
```
```bash npm install @auth0/angular-jwt npm install --save angular-oauth2-oidc ```
```bash
npm install @auth0/angular-jwt
npm install --save angular-oauth2-oidc
```

 2. Creating an Authentication Service

The authentication service will handle the login, logout, and token management. Below is a simple example of how to create an authentication service in Angular.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```typescript
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { JwtHelperService } from '@auth0/angular-jwt';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private apiUrl = 'https://example.com/api/auth';
private tokenKey = 'auth_token';
constructor(private http: HttpClient, private router: Router, private jwtHelper: JwtHelperService) {}
login(credentials: any) {
return this.http.post(`${this.apiUrl}/login`, credentials)
.subscribe((response: any) => {
localStorage.setItem(this.tokenKey, response.token);
this.router.navigate(['/dashboard']);
});
}
logout() {
localStorage.removeItem(this.tokenKey);
this.router.navigate(['/login']);
}
isAuthenticated(): boolean {
const token = localStorage.getItem(this.tokenKey);
return token ? !this.jwtHelper.isTokenExpired(token) : false;
}
getToken(): string | null {
return localStorage.getItem(this.tokenKey);
}
}
```
```typescript import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Router } from '@angular/router'; import { JwtHelperService } from '@auth0/angular-jwt'; @Injectable({ providedIn: 'root' }) export class AuthService { private apiUrl = 'https://example.com/api/auth'; private tokenKey = 'auth_token'; constructor(private http: HttpClient, private router: Router, private jwtHelper: JwtHelperService) {} login(credentials: any) { return this.http.post(`${this.apiUrl}/login`, credentials) .subscribe((response: any) => { localStorage.setItem(this.tokenKey, response.token); this.router.navigate(['/dashboard']); }); } logout() { localStorage.removeItem(this.tokenKey); this.router.navigate(['/login']); } isAuthenticated(): boolean { const token = localStorage.getItem(this.tokenKey); return token ? !this.jwtHelper.isTokenExpired(token) : false; } getToken(): string | null { return localStorage.getItem(this.tokenKey); } } ```
```typescript
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { JwtHelperService } from '@auth0/angular-jwt';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private apiUrl = 'https://example.com/api/auth';
  private tokenKey = 'auth_token';

  constructor(private http: HttpClient, private router: Router, private jwtHelper: JwtHelperService) {}

  login(credentials: any) {
    return this.http.post(`${this.apiUrl}/login`, credentials)
      .subscribe((response: any) => {
        localStorage.setItem(this.tokenKey, response.token);
        this.router.navigate(['/dashboard']);
      });
  }

  logout() {
    localStorage.removeItem(this.tokenKey);
    this.router.navigate(['/login']);
  }

  isAuthenticated(): boolean {
    const token = localStorage.getItem(this.tokenKey);
    return token ? !this.jwtHelper.isTokenExpired(token) : false;
  }

  getToken(): string | null {
    return localStorage.getItem(this.tokenKey);
  }
}
```

 3. Adding HTTP Interceptors for Token Management

To ensure that every HTTP request includes the JWT, you can use an HTTP interceptor.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```typescript
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = this.authService.getToken();
if (token) {
const cloned = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`)
});
return next.handle(cloned);
}
return next.handle(req);
}
}
```
```typescript import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; import { AuthService } from './auth.service'; @Injectable() export class JwtInterceptor implements HttpInterceptor { constructor(private authService: AuthService) {} intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const token = this.authService.getToken(); if (token) { const cloned = req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) }); return next.handle(cloned); } return next.handle(req); } } ```
```typescript
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

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

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

In your Angular module, ensure that the interceptor is provided:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```typescript
import { HTTP_INTERCEPTORS } from '@angular/common/http';
@NgModule({
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }
]
})
export class AppModule {}
```
```typescript import { HTTP_INTERCEPTORS } from '@angular/common/http'; @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true } ] }) export class AppModule {} ```
```typescript
import { HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }
  ]
})
export class AppModule {}
```

 4. Protecting Routes with Guards

To protect certain routes and ensure only authenticated users can access them, use Angular route guards.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```typescript
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.isAuthenticated()) {
return true;
}
this.router.navigate(['/login']);
return false;
}
}
```
```typescript 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.isAuthenticated()) { return true; } this.router.navigate(['/login']); return false; } } ```
```typescript
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.isAuthenticated()) {
      return true;
    }
    this.router.navigate(['/login']);
    return false;
  }
}
```

Use the guard in your routing module:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```typescript
import { AuthGuard } from './auth.guard';
const routes: Routes = [
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
{ path: '', redirectTo: 'login' }
];
```
```typescript import { AuthGuard } from './auth.guard'; const routes: Routes = [ { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent }, { path: '', redirectTo: 'login' } ]; ```
```typescript
import { AuthGuard } from './auth.guard';

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

 5. Handling Token Expiration and Refresh

JWT tokens are typically short-lived. To handle token expiration, you can implement a token refresh mechanism.

Example of handling token refresh:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
```typescript
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { JwtHelperService } from '@auth0/angular-jwt';
@Injectable({
providedIn: 'root'
})
export class TokenService {
private refreshTokenUrl = 'https://example.com/api/auth/refresh-token';
constructor(private http: HttpClient, private jwtHelper: JwtHelperService) {}
refreshToken() {
const token = localStorage.getItem('auth_token');
if (token && this.jwtHelper.isTokenExpired(token)) {
return this.http.post(this.refreshTokenUrl, { token });
}
return null;
}
}
```
```typescript import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { JwtHelperService } from '@auth0/angular-jwt'; @Injectable({ providedIn: 'root' }) export class TokenService { private refreshTokenUrl = 'https://example.com/api/auth/refresh-token'; constructor(private http: HttpClient, private jwtHelper: JwtHelperService) {} refreshToken() { const token = localStorage.getItem('auth_token'); if (token && this.jwtHelper.isTokenExpired(token)) { return this.http.post(this.refreshTokenUrl, { token }); } return null; } } ```
```typescript
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { JwtHelperService } from '@auth0/angular-jwt';

@Injectable({
  providedIn: 'root'
})
export class TokenService {
  private refreshTokenUrl = 'https://example.com/api/auth/refresh-token';
  
  constructor(private http: HttpClient, private jwtHelper: JwtHelperService) {}

  refreshToken() {
    const token = localStorage.getItem('auth_token');
    if (token && this.jwtHelper.isTokenExpired(token)) {
      return this.http.post(this.refreshTokenUrl, { token });
    }
    return null;
  }
}
```

 Conclusion

Implementing JWT-based authentication in Angular provides a robust and scalable method for securing user data. By following the steps outlined in this article, you can ensure that your Angular application is protected against unauthorized access while maintaining a seamless user experience.

 Further Reading:

  1. Angular Official Documentation
  2. Auth0 JWT Documentation
  3. Angular HTTP Interceptors
Previously at
Flag Argentina
Mexico
time icon
GMT-6
Experienced Engineering Manager and Senior Frontend Engineer with 9+ years of hands-on experience in leading teams and developing frontend solutions. Proficient in Angular JS