How to implement an authentication layer using HTTP interceptor in Angular

Angular
3 minutes read

Introduction

Authentication is fundamental for many applications and this is one of the most common use cases for interceptors. In this article, I’ll walk you through how to use an HTTP interceptor to catch all HTTP requests and add a token header.

Project Setup

Let’s create a brand new project and the needed components and services using the following commands:

  • ng new interceptor-auth (to create a brand new project named interceptor-auth)
  • ng g interceptor interceptors/auth (to create an auth interceptor)
  • ng g s services/auth (to create an auth service)

You should end with the following folder structure

Working With The Interceptor

Let’s add the following code snippet to the auth.service.ts

import {Injectable} from '@angular/core';

@Injectable({
   providedIn: 'root'
})
export class AuthService {

   get token(): string {
       return "This is a dump token";
   }

   // Return true if the token exists
   isAuthenticated(): boolean {
       return !!this.token;
   }
}

The AuthService here has a method called isAuthenticated() which tells us if there is a valid token (in real-world applications, you should check if the token is in the right format, and is not expired), and it has a token variable with a dummy string which represents the token (in real-world applications the token will be received from the backend and stored in the local storage, session storage or the cookies depends on your requirements).

Let’s take a look at the auth.interceptor.ts file.

import {Injectable} from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

   constructor() {
   }

   intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
        return next.handle(request);
   }
}

Notice that it implements the HttpInterceptor interface, which forces us to implement the intercept function which identifies and handles a given HTTP request.

What about the intercept function parameters? 

  • req– The outgoing request object to handle.
  • next – The next interceptor in the chain, or the backend if no interceptors remain in the chain.
  • Returns: an observable of the event stream.

Let’s add the following code snippet to the auth.interceptor.ts

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

   constructor(private authService: AuthService) {
   }

   intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
       const isAuthenticated = this.authService.isAuthenticated()

       if (isAuthenticated) {
           const token = this.authService.token

           const clonedReq = request.clone({
               headers: request.headers.set('Authorization', token)
           })

           return next.handle(clonedReq)
       } else {
           return next.handle(request);
       }
   }
}

The logic is simple, if the user IS NOT authenticated, the request will be sent without any modification. But, if the user IS authenticated, then we will clone the original request (since the original request is immutable and cannot be edited directly) and set a new header with a key of Authorization and the value of the dummy token from the auth.service.ts

Now, let’s tell the Angular to use this interceptor, we do this by adding the following in the app.module.ts

...
import {HTTP_INTERCEPTORS} from "@angular/common/http";
import {AuthInterceptor} from "./interceptors/auth.interceptor";

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

At this point, we implemented the logic that will add the authorization token to the request header and send it to the backend (if the user is authorized).

Speaking of requests, we will use the JSONPlaceholder as a fake API to test our work.

Test Our Work

Add the following code snippet to start testing

// app.component.ts

export class AppComponent {
   url = 'https://jsonplaceholder.typicode.com/posts'

   constructor(private httpClient: HttpClient) {
   }


   getData() {
       this.httpClient.get(this.url).subscribe(
           res => {
               console.log(res);
           }, error => {
               console.log(error);
           })
   }
}
<!-- app.component.html →

<button (click)="getData()">Get Data</button>

If we tried to click on the button and inspect the request we should see the authorization token added

And, if we cleared the dummy token (token = ''), and tried again. Then we shouldn’t see the authorization token since the user isn’t authenticated.

Further Reading

Conclusion

This was a basic implementation of how we could use the HTTP interceptor to add the token header for authenticated users. You could take this idea to the next stage and use it to add custom HTTP headers for all or some HTTP requests. Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *