Authentication Patterns

Back

Loading concept...

HTTP Client Authentication Patterns in Angular

The Story of the Secret Clubhouse

Imagine you have a secret clubhouse. Not everyone can enter! You need a special wristband to get in. This wristband proves who you are.

In the web world, this wristband is called a JWT (JSON Web Token). And the guards at the door? Those are Route Guards!


What is JWT?

JWT stands for JSON Web Token. Think of it as a digital ID card.

When you log into an app:

  1. The server checks your username and password
  2. If correct, the server gives you a JWT token
  3. You show this token every time you want something

Real Life Example:

  • You buy a movie ticket (login)
  • You get a ticket stub (JWT token)
  • You show it to enter any theater room (access resources)

What’s Inside a JWT?

A JWT has 3 parts separated by dots:

header.payload.signature
graph TD A["JWT Token"] --> B["Header"] A --> C["Payload"] A --> D["Signature"] B --> E["Algorithm type"] C --> F["User data"] D --> G["Verification"]

Interceptors: Your Automatic Helper

Imagine having a helper robot that:

  • Automatically puts your wristband on every request
  • You never forget to show it!

This is what an HTTP Interceptor does in Angular.

Creating a JWT Interceptor

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

@Injectable()
export class AuthInterceptor
  implements HttpInterceptor {

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ) {
    // Get token from storage
    const token = localStorage
      .getItem('jwt_token');

    // If we have a token
    if (token) {
      // Clone request, add token
      const authReq = req.clone({
        setHeaders: {
          Authorization:
            `Bearer ${token}`
        }
      });
      return next.handle(authReq);
    }

    return next.handle(req);
  }
}

Registering the Interceptor

In your app.config.ts or module:

import {
  provideHttpClient,
  withInterceptors
} from '@angular/common/http';
import { authInterceptor }
  from './auth.interceptor';

export const appConfig = {
  providers: [
    provideHttpClient(
      withInterceptors([
        authInterceptor
      ])
    )
  ]
};

How It Works

graph TD A["Your Request"] --> B["Interceptor"] B --> C{Has Token?} C -->|Yes| D["Add Token to Header"] C -->|No| E["Send Original Request"] D --> F["Send to Server"] E --> F

Route Guards: The Door Protectors

Remember the guards at the clubhouse? In Angular, they’re called Route Guards.

Guards answer one question: “Can this person enter?”

Types of Guards

Guard Type Question Asked
CanActivate Can they enter?
CanDeactivate Can they leave?
CanMatch Can they see this route?

Creating an Auth Guard

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

export const authGuard = () => {
  const authService =
    inject(AuthService);
  const router =
    inject(Router);

  if (authService.isLoggedIn()) {
    return true;
  }

  // Redirect to login page
  router.navigate(['/login']);
  return false;
};

Using Guards in Routes

import { Routes } from
  '@angular/router';
import { authGuard } from
  './auth.guard';

export const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [authGuard]
  },
  {
    path: 'profile',
    component: ProfileComponent,
    canActivate: [authGuard]
  },
  {
    path: 'login',
    component: LoginComponent
  }
];

Guard Flow

graph TD A["User clicks link"] --> B["Router checks guard"] B --> C{Guard returns?} C -->|true| D["Go to page"] C -->|false| E["Redirect to login"]

The Complete Authentication Flow

Let’s see how JWT and Guards work together!

graph TD A["User enters site"] --> B{Has valid token?} B -->|No| C["Show Login Page"] B -->|Yes| D["Guard allows entry"] C --> E["User logs in"] E --> F["Server sends JWT"] F --> G["Store token locally"] G --> H["User accesses pages"] H --> I["Interceptor adds token"] I --> J["Server validates"]

Step by Step

  1. User logs in with username/password
  2. Server validates and returns JWT
  3. App stores JWT in localStorage
  4. User navigates to protected page
  5. Guard checks if token exists
  6. Interceptor attaches token to all requests
  7. Server validates token on each request

Building the Auth Service

The Auth Service is the brain of authentication:

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

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private loggedIn =
    new BehaviorSubject<boolean>(
      this.hasToken()
    );

  constructor(
    private http: HttpClient
  ) {}

  login(email: string, pw: string) {
    return this.http.post<{token: string}>(
      '/api/login',
      { email, password: pw }
    ).pipe(
      tap(response => {
        localStorage.setItem(
          'jwt_token',
          response.token
        );
        this.loggedIn.next(true);
      })
    );
  }

  logout() {
    localStorage.removeItem(
      'jwt_token'
    );
    this.loggedIn.next(false);
  }

  isLoggedIn(): boolean {
    return this.hasToken();
  }

  private hasToken(): boolean {
    return !!localStorage
      .getItem('jwt_token');
  }

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

Handling Token Expiration

JWT tokens expire! Like a movie ticket that’s only valid today.

Checking Expiration

isTokenExpired(): boolean {
  const token = this.getToken();
  if (!token) return true;

  // JWT has 3 parts
  const payload = token
    .split('.')[1];
  const decoded = JSON.parse(
    atob(payload)
  );

  // exp is expiration time
  const expiry = decoded.exp;
  const now = Math.floor(
    Date.now() / 1000
  );

  return expiry < now;
}

Interceptor with Expiration Check

intercept(req, next) {
  const token = this.auth.getToken();

  if (token) {
    if (this.auth.isTokenExpired()) {
      // Token expired, logout
      this.auth.logout();
      this.router.navigate(['/login']);
      return EMPTY;
    }

    const authReq = req.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`
      }
    });
    return next.handle(authReq);
  }

  return next.handle(req);
}

Error Handling in Interceptor

What if the server rejects our token?

intercept(req, next) {
  const token = this.auth.getToken();

  let authReq = req;
  if (token) {
    authReq = req.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`
      }
    });
  }

  return next.handle(authReq).pipe(
    catchError((error) => {
      if (error.status === 401) {
        // Unauthorized - token invalid
        this.auth.logout();
        this.router.navigate(['/login']);
      }
      return throwError(() => error);
    })
  );
}

Quick Summary

Concept What It Does
JWT Digital ID card from server
Interceptor Automatically adds token to requests
Guard Protects routes from unauthorized access
Auth Service Manages login, logout, and token storage

Remember This!

  • JWT = Your ticket to the clubhouse
  • Interceptor = Helper that shows your ticket automatically
  • Guard = The door security checking your ticket
  • Auth Service = The manager who gives and takes tickets

You’re now ready to secure your Angular app like a pro! Every request is protected, every route is guarded, and your users are safe.

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.