Securing Angular HTTP Requests: Authentication and Retry Patterns

Photo by Jess Bailey on Unsplash

Securing Angular HTTP Requests: Authentication and Retry Patterns

Introduction

When working with Angular applications, handling authentication tokens and retrying failed HTTP requests are common challenges. Angular provides a powerful feature called HTTP Interceptors, which allows developers to:

✅ Automatically attach authentication tokens to outgoing requests
✅ Retry failed requests automatically
✅ Centralize HTTP request modifications for cleaner code

In this blog, we will explore how to create and use HTTP Interceptors in Angular for:
1️⃣ Adding Authorization Headers dynamically
2️⃣ Retrying Failed Requests Automatically

We will also demonstrate how to test an HTTP interceptor dynamically using an input-based API URL fetcher.


🔹 Setting Up HTTP Interceptors in Angular

In our project, we have two interceptors:

📌 auth.interceptor.ts → Adds a Bearer auth token to every request
📌 retry.interceptor.tsRetries failed requests up to 2 times before throwing an error

These interceptors are provided globally in app.config.ts.


🔹 1️⃣ Creating an Authentication Interceptor

Goal: Attach a dynamic Authorization token from localStorage to every outgoing request.

📌 auth.interceptor.ts

import {
  HttpRequest,
  HttpHandlerFn,
  HttpEvent,
  HttpInterceptorFn,
} from '@angular/common/http';
import { Observable } from 'rxjs';

export const authInterceptorFn: HttpInterceptorFn = (
  req: HttpRequest<any>,
  next: HttpHandlerFn
): Observable<HttpEvent<any>> => {
  const authToken = localStorage.getItem('authToken');

  if (authToken) {
    const authReq = req.clone({
      setHeaders: {
        Authorization: `Bearer ${authToken}`,
      },
    });
    return next(authReq);
  }

  return next(req);
};

🔹 How It Works?

✔ Fetches authToken from localStorage
✔ If the token exists, modifies the request to include the Authorization header
✔ Passes the modified request to the next handler


🔹 2️⃣ Implementing an HTTP Retry Interceptor

Goal: Automatically retry failed requests up to 2 times before throwing an error.

📌 retry.interceptor.ts

import {
  HttpRequest,
  HttpHandlerFn,
  HttpEvent,
  HttpInterceptorFn,
} from '@angular/common/http';
import { Observable, retry } from 'rxjs';

export const retryInterceptorFn: HttpInterceptorFn = (
  req: HttpRequest<any>,
  next: HttpHandlerFn
): Observable<HttpEvent<any>> => {
  return next(req).pipe(retry(2)); // Retries failed requests twice
};

🔹 Why Use Retry Logic?

✔ Handles temporary network failures
✔ Improves user experience by automatically retrying failed requests
✔ Reduces manual error handling


🔹 3️⃣ Providing Interceptors Globally

Once we create the interceptors, we must register them globally in app.config.ts:

📌 app.config.ts

import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authInterceptorFn } from './interceptors/auth.interceptor';
import { retryInterceptorFn } from './interceptors/retry.interceptor';

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter([]),
    provideHttpClient(
      withInterceptors([authInterceptorFn, retryInterceptorFn])
    ),
  ],
};

Now, all HTTP requests in the app will automatically:
✅ Include the Authorization token
Retry on failure (up to 2 times)


🔹 4️⃣ Testing Interceptors with Dynamic API Fetching

We will now create a simple API Fetching Component, where users can enter an API URL and fetch data. The response will be displayed dynamically, and both interceptors will work behind the scenes.


📌 app.component.ts

import { JsonPipe } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, inject, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-root',
  imports: [FormsModule, JsonPipe],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent implements OnInit {
  title = 'angular-examples';

  response: string = '';
  apiUrl: string = 'https://jsonplaceholder.typicode.com/todos/1';

  http = inject(HttpClient);

  constructor() {}

  ngOnInit() {
    localStorage.setItem('authToken', 'your_dynamic_test_token');
  }

  fetchData() {
    this.http.get(this.apiUrl).subscribe({
      next: (data: any) => {
        this.response = data;
      },
      error: (error) => {
        this.response = `Error: ${error.message}`;
      },
    });
  }
}

🔹 5️⃣ Creating the HTML Template

📌 app.component.html

<h1>Dynamic HTTP Interceptor Test</h1>
<label>URL: <input type="text" [(ngModel)]="apiUrl" /></label><br />
<button (click)="fetchData()">Fetch Data</button>
@if(response){
<p>{{ response | json }}</p>
}

🔹 6️⃣ Styling the UI

📌 app.component.css

h1 {
  text-align: center;
  margin-bottom: 20px;
  color: #333;
}

label {
  display: block;
  margin-bottom: 10px;
  font-weight: bold;
  width: 100%;
}

input[type="text"] {
  width: calc(100% - 18px);
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 16px;
  box-sizing: border-box;
}

button {
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  margin-top: 10px;
}

button:hover {
  background-color: #0056b3;
}

p {
  margin-top: 20px;
  padding: 10px;
  border: 1px solid #eee;
  background-color: #f9f9f9;
  white-space: pre-wrap;
  word-wrap: break-word;
}

🔹 How to Test the Interceptors?

1️⃣ Run the Application

ng serve

2️⃣ Enter an API URL (e.g., https://jsonplaceholder.typicode.com/todos/1)
3️⃣
Click "Fetch Data" to see the response
4️⃣ Check Browser DevTools > Network Tab

  • Requests will include Authorization Headers

  • Failed requests will retry automatically


🔹 Key Takeaways

Authentication Interceptor adds a Bearer token dynamically
Retry Interceptor retries failed requests up to 2 times
Global Interceptor Registration ensures all requests are modified automatically
Dynamic API Fetching helps test interceptors in real-time


🔹 Final Thoughts

Using Angular HTTP Interceptors, we can efficiently handle authentication and error retries without modifying individual API calls. This improves maintainability and performance.

Exploring the Code

Visit the GitHub repository to explore the code in detail.

Live Demo

Check out the working example on StackBlitz


Additional Resources

Feel free to leave comments or questions below! 👋