All posts

Introduction: Security is a Requirement, Not an Option

Introduction: Security is a Requirement, Not an Option

Modern Angular applications handle sensitive data: admin dashboards, user profiles, analytics panels. Without proper protection, your application becomes an open door to unauthorized access and data leaks.

Angular provides powerful tools like Route Guards and HTTP Interceptors to build a layered security system.


Section 1: Protecting Admin Dashboard (Real Use Case)

Scenario: You built an admin panel for managing blog posts. Only authenticated admins should access /admin.


export const adminGuard: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const router = inject(Router);

  if (!auth.isAuthenticated()) {
    return router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url } });
  }

  if (!auth.hasRole('admin')) {
    return router.createUrlTree(['/403']);
  }

  return true;
};

✅ Result: Unauthorized users are blocked before the page even loads.


Section 2: Prevent Download of Admin Module (Real Use Case)

Scenario: Your admin module is lazy-loaded. Without protection, users could still download the code by typing the URL manually.


export const canMatchAdmin: CanMatchFn = () => {
  const auth = inject(AuthService);
  return auth.isAuthenticated() && auth.hasRole('admin');
};

✅ Result: The admin bundle is never downloaded if the user is not authorized.


Section 3: Unsaved Form Protection (Real Use Case)

Scenario: User is writing a blog article and accidentally clicks another page.


export const dirtyFormGuard: CanDeactivateFn<any> = component => {
  if (!component.isDirty()) return true;
  return window.confirm('You have unsaved changes. Continue?');
};

✅ Result: No more lost work.


Section 4: Attach JWT Token Automatically (Real Use Case)

Scenario: Every API request must include authentication token.


export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const auth = inject(AuthService);
  const token = auth.getToken();

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

  return next(cloned);
};

✅ Result: Secure communication without repeating code everywhere.


Section 5: Global Error Handling (Real Use Case)

Scenario: Token expires while user is browsing.


catchError((err: HttpErrorResponse) => {
  if (err.status === 401) {
    auth.logout();
    router.navigate(['/login']);
  }
  return throwError(() => err);
});

✅ Result: Automatic logout and session protection.


Section 6: Daily Use Case – Security Mindset

Security is not only code. It’s also daily habits:

  • Never trust user input
  • Validate everything on backend
  • Do not store sensitive data in localStorage
  • Always handle errors properly

Conclusion

Security is not a single feature. It’s a system.

By combining Guards, Interceptors, and backend validation, you build applications that are not only functional, but also reliable and professional.