#angular #auth #jwt #security

Day 8 β€” Authentication, JWT, Guards, Interceptors & Auth Store

πŸ“˜ Day 8 β€” Authentication, JWT, Guards, Interceptors & Auth Store

Zero to Hero β€” Hands-on Angular Tutorial

Today you will build:

  • βœ”οΈ Login page
  • βœ”οΈ AuthService (signals + localStorage)
  • βœ”οΈ JWT storage
  • βœ”οΈ HTTP Interceptor attaching Authorization headers
  • βœ”οΈ AuthGuard blocking unauthorized pages
  • βœ”οΈ Auto-redirect after login
  • βœ”οΈ Logout function
  • βœ”οΈ Protected dashboard page

This is real-world Angular authentication. Let’s do it! πŸš€


🟦 1. Create AuthService (Signal-based Authentication Store)

Generate:

ng g service auth/auth

Open: auth.service.ts

import { Injectable, signal, computed, effect, inject } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  private http = inject(HttpClient);
  private router = inject(Router);

  private apiUrl = 'https://reqres.in/api/login'; // mock login endpoint

  token = signal<string | null>(localStorage.getItem('token'));

  isLoggedIn = computed(() => !!this.token());

  constructor() {
    effect(() => {
      if (this.token()) {
        localStorage.setItem('token', this.token()!);
      } else {
        localStorage.removeItem('token');
      }
    });
  }

  login(email: string, password: string) {
    return this.http
      .post<{ token: string }>(this.apiUrl, { email, password })
      .subscribe({
        next: (res) => {
          this.token.set(res.token);
          this.router.navigate(['/dashboard']);
        },
        error: () => alert('Invalid credentials'),
      });
  }

  logout() {
    this.token.set(null);
    this.router.navigate(['/login']);
  }
}
  • βœ”οΈ Uses signals
  • βœ”οΈ Persists login state
  • βœ”οΈ Auto-navigates on login/logout
  • βœ”οΈ Works with mock API
  • βœ”οΈ Ready to plug into real backend

🟩 2. Create Login Page

Generate:

ng g component pages/login --standalone

login.component.ts

import { Component, inject } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
import { AuthService } from '../../auth/auth.service';

@Component({
  selector: 'app-login',
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './login.component.html',
})
export class LoginComponent {
  fb = inject(FormBuilder);
  auth = inject(AuthService);

  form = this.fb.group({
    email: ['', [Validators.required, Validators.email]],
    password: ['', Validators.required],
  });

  submit() {
    if (this.form.invalid) return;

    const { email, password } = this.form.value;
    this.auth.login(email!, password!);
  }
}

login.component.html

<h2>Login</h2>

<form [formGroup]="form" (ngSubmit)="submit()">
  <label>Email</label>
  <input formControlName="email" />
  <div *ngIf="form.controls['email'].touched && form.controls['email'].invalid">
    Enter a valid email
  </div>

  <label>Password</label>
  <input type="password" formControlName="password" />
  <div *ngIf="form.controls['password'].touched && form.controls['password'].invalid">
    Password is required
  </div>

  <button type="submit">Login</button>
</form>
  • βœ”οΈ A real login form
  • βœ”οΈ Validates input
  • βœ”οΈ Calls AuthService

πŸŸ₯ 3. Create Dashboard (Protected Page)

Generate:

ng g component pages/dashboard --standalone

dashboard.component.ts

import { Component, inject } from '@angular/core';
import { AuthService } from '../../auth/auth.service';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  templateUrl: './dashboard.component.html',
})
export class DashboardComponent {
  auth = inject(AuthService);
}

dashboard.component.html

<h2>Dashboard</h2>

<p>Welcome! You are logged in.</p>

<button (click)="auth.logout()">Logout</button>
  • βœ”οΈ Accessible only after login
  • βœ”οΈ Includes logout

🟧 4. Add AuthGuard

Generate:

ng g guard auth/auth --standalone

Open: auth.guard.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;
  } else {
    router.navigate(['/login']);
    return false;
  }
};
  • βœ”οΈ Protects routes
  • βœ”οΈ Redirects automatically
  • βœ”οΈ Based on signal state

🟦 5. Protect Routes

Open: app.routes.ts

import { authGuard } from './auth/auth.guard';

export const routes: Routes = [
  { path: 'login', loadComponent: () => import('./pages/login/login.component').then(m => m.LoginComponent) },

  {
    path: 'dashboard',
    canActivate: [authGuard],
    loadComponent: () => import('./pages/dashboard/dashboard.component').then(m => m.DashboardComponent)
  },

  { path: '', redirectTo: 'login', pathMatch: 'full' }
];
  • βœ”οΈ Dashboard is protected
  • βœ”οΈ Login remains public

🟧 6. Add JWT to Every Request (Auth Interceptor)

Generate:

ng g interceptor auth/auth

auth.interceptor.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);

  const cloned = req.clone({
    setHeaders: {
      Authorization: `Bearer ${token}`,
    },
  });

  return next(cloned);
};

Add to providers (main.ts or app.config.ts):

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

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(withInterceptors([authInterceptor]))
  ]
});
  • βœ”οΈ Automatically attaches JWT
  • βœ”οΈ Works for all API requests
  • βœ”οΈ Clean and centralized

🟩 7. Auto-Logout (Optional Bonus)

Inside AuthService:

autoLogoutAfter(ms: number) {
  setTimeout(() => this.logout(), ms);
}

Call after login:

this.autoLogoutAfter(3600_000); // 1 hour

🟫 8. Show Login State in Navbar

In AppComponent:

import { AuthService } from './auth/auth.service';

auth = inject(AuthService);

app.component.html:

<nav>
  <a routerLink="/login" *ngIf="!auth.isLoggedIn()">Login</a>
  <a routerLink="/dashboard" *ngIf="auth.isLoggedIn()">Dashboard</a>
  <button *ngIf="auth.isLoggedIn()" (click)="auth.logout()">Logout</button>
</nav>

<router-outlet></router-outlet>
  • βœ”οΈ Reactive navbar
  • βœ”οΈ No RxJS
  • βœ”οΈ Pure signal goodness

πŸŽ‰ End of Day 8 β€” What You Achieved

Today you built:

  • βœ”οΈ Login form
  • βœ”οΈ AuthService with signals
  • βœ”οΈ AuthGuard
  • βœ”οΈ AuthInterceptor
  • βœ”οΈ Protected dashboard
  • βœ”οΈ LocalStorage persistence
  • βœ”οΈ Auto navigation on login/logout
  • βœ”οΈ Enterprise authentication pattern

This is a complete, modern Angular authentication setup. You are really leveling up πŸ’ͺπŸ”₯


πŸ§ͺ Day 8 Challenge

Build a Profile Page that:

  1. is protected by AuthGuard
  2. loads user info from an API
  3. uses authInterceptor for token
  4. has a logout button
  5. shows UI only when logged in