JWT Authentication in Angular (Guard + Interceptor Pattern)
Put together the standard real-world auth flow: login, store token, intercept API calls, protect routes.
A standard Angular JWT setup has 3 parts: 1) Auth service (login + token storage) 2) HTTP interceptor (attach token) 3) Route guard (block protected pages) ## 1) Auth service ```ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { tap } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthService { constructor(private http: HttpClient) {} login(email: string, password: string) { return this.http.post<{ token: string }>('/api/login', { email, password }).pipe( tap(res => localStorage.setItem('token', res.token)) ); } logout() { localStorage.removeItem('token'); } get token() { return localStorage.getItem('token'); } get isLoggedIn() { return !!this.token; } } ``` ## 2) Interceptor (attach token) ```ts import { HttpInterceptorFn } from '@angular/common/http'; import { inject } from '@angular/core'; import { AuthService } from './auth.service'; export const authInterceptor: HttpInterceptorFn = (req, next) => { const auth = inject(AuthService); const token = auth.token; if (!token) return next(req); return next( req.clone({ setHeaders: { Authorization: `Bearer ${token}` }, }) ); }; ``` ## 3) Guard (protect routes) ```ts import { CanActivateFn, Router } from '@angular/router'; import { inject } from '@angular/core'; import { AuthService } from './auth.service'; export const authGuard: CanActivateFn = () => { const auth = inject(AuthService); const router = inject(Router); if (auth.isLoggedIn) return true; router.navigate(['/login']); return false; }; ``` ## Visual: request flow ```mermaid flowchart LR UI[Component] --> API[HttpClient Request] API --> INT[Interceptor adds token] INT --> BE[Backend] BE --> INT INT --> UI ``` > Next: Token refresh and handling 401 responses gracefully.