How to Add Authentication to an Angular App

How to Add Authentication to an Angular App

How to Add Authentication to an Angular App

Secure your Angular application with a complete JWT authentication flow — login, token storage, protected routes, and automatic token refresh.

Step 1 — Auth Service with Signals

// services/auth.service.ts
@Injectable({ providedIn: 'root' })
export class AuthService {
  private http   = inject(HttpClient);
  private router = inject(Router);

  private _token = signal<string | null>(localStorage.getItem('token'));
  private _user  = signal<User | null>(JSON.parse(localStorage.getItem('user') ?? 'null'));

  readonly token        = this._token.asReadonly();
  readonly user         = this._user.asReadonly();
  readonly isLoggedIn   = computed(() => !!this._token());

  login(email: string, password: string): Observable<void> {
    return this.http.post<{ token: string; user: User }>('/api/login', { email, password }).pipe(
      tap(({ token, user }) => {
        this._token.set(token);
        this._user.set(user);
        localStorage.setItem('token', token);
        localStorage.setItem('user', JSON.stringify(user));
      }),
      map(() => void 0)
    );
  }

  logout(): void {
    this._token.set(null);
    this._user.set(null);
    localStorage.removeItem('token');
    localStorage.removeItem('user');
    this.router.navigate(['/login']);
  }
}

Step 2 — Auth Guard

// guards/auth.guard.ts
export const authGuard: CanActivateFn = () => {
  const auth   = inject(AuthService);
  const router = inject(Router);
  return auth.isLoggedIn() ? true : router.createUrlTree(['/login']);
};

Step 3 — Apply Guard to Routes

export const routes: Routes = [
  { path: 'login',     loadComponent: () => import('./login/login.component').then(m => m.LoginComponent) },
  { path: 'dashboard', loadComponent: () => import('./dashboard/dashboard.component').then(m => m.DashboardComponent),
    canActivate: [authGuard] },
];

Step 4 — Login Component

@Component({ standalone: true, imports: [ReactiveFormsModule], template: `...` })
export class LoginComponent {
  private auth = inject(AuthService);
  private router = inject(Router);

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

  onSubmit(): void {
    if (this.form.invalid) return;
    const { email, password } = this.form.value;
    this.auth.login(email!, password!).subscribe({
      next: () => this.router.navigate(['/dashboard']),
      error: err => console.error(err),
    });
  }
}
All Comments