← Back to Article List         
Redirect an Unauthenticated User to the Login Page

Redirect an Unauthenticated User to the Login Page

Published on 30 Sep 2026     7 min read Angular
Route Guards

How Do You Redirect an Unauthenticated User to the Login Page?

In Angular, we commonly use a CanActivateFn authentication guard.

The guard:

  1. Checks whether the user is authenticated.
  2. Returns true if authenticated.
  3. Returns a redirect to /login if not authenticated.
User → /dashboard
          ↓
      authGuard
          ↓
     Logged in?
       /    \
     Yes     No
      ↓       ↓
 Dashboard  /login

Full Simple Program

auth.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  private loggedIn = false;

  login(): void {
    this.loggedIn = true;
  }

  logout(): void {
    this.loggedIn = false;
  }

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

auth.guard.ts

import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';

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

export const authGuard: CanActivateFn = (route, state) => {

  const authService = inject(AuthService);
  const router = inject(Router);

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

  return router.createUrlTree(['/login']);
};

dashboard.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  template: `
    <h2>Dashboard</h2>
    <p>Welcome to Dashboard.</p>
  `
})
export class Dashboard {
}

login.ts

import { Component } from '@angular/core';
import { Router } from '@angular/router';

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

@Component({
  selector: 'app-login',
  standalone: true,
  template: `
    <h2>Login</h2>

    <button (click)="login()">
      Login
    </button>
  `
})
export class Login {

  constructor(
    private authService: AuthService,
    private router: Router
  ) {
  }

  login(): void {

    this.authService.login();

    this.router.navigate(['/dashboard']);
  }
}

app.routes.ts

import { Routes } from '@angular/router';

import { Login } from './login';
import { Dashboard } from './dashboard';
import { authGuard } from './auth.guard';

export const routes: Routes = [
  {
    path: 'login',
    component: Login
  },
  {
    path: 'dashboard',
    component: Dashboard,
    canActivate: [authGuard]
  }
];

app.config.ts

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes)
  ]
};

How Does the Redirect Work?

The important code is:

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

return router.createUrlTree(['/login']);

If the user is authenticated:

/dashboard
    ↓
authGuard
    ↓
isLoggedIn() = true
    ↓
Dashboard

If not:

/dashboard
    ↓
authGuard
    ↓
isLoggedIn() = false
    ↓
Return /login redirect
    ↓
Login

Why Return a Redirect Instead of Calling navigate()?

You may see:

router.navigate(['/login']);
return false;

A cleaner guard approach is:

return router.createUrlTree(['/login']);

The guard simply tells the Router:

Don't activate this route. Redirect to /login.


Redirect Back to the Original Page After Login

A common real-world requirement is:

User requests /orders
        ↓
Not logged in
        ↓
/login
        ↓
User logs in
        ↓
Return to /orders

The guard can preserve the requested URL:

export const authGuard: CanActivateFn = (route, state) => {

  const authService = inject(AuthService);
  const router = inject(Router);

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

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

If the user requested:

/orders

Angular redirects to:

/login?returnUrl=/orders

After successful login, the application can read returnUrl and navigate back to /orders.


2. Can Route Guards Provide Real Security Without Backend Authorization?

No.

This is a very important Angular + ASP.NET Core interview point.

Angular route guards do not provide actual backend security.

They primarily control client-side navigation and user experience.

Angular Guard
     ↓
Protects navigation in browser
     ↓
NOT the backend API

Why Isn't a Route Guard Enough?

Angular executes inside the user's browser.

Suppose Angular protects:

/admin

with:

{
  path: 'admin',
  component: Admin,
  canActivate: [adminGuard]
}

A normal user might be prevented from navigating to:

/admin

through the Angular application.

But your backend might expose:

GET /api/admin/users

An attacker doesn't have to use your Angular application.

They could directly call the API using tools such as an HTTP client.

Angular
   ↓
Guard blocks /admin


But attacker
   ↓
Direct HTTP request
   ↓
GET /api/admin/users

If the backend doesn't authorize the request, the Angular guard cannot protect that API.


Correct Architecture

For an Angular + ASP.NET Core application:

              Browser
                 │
                 ▼
              Angular
                 │
          Route Guard
                 │
      Controls UI Navigation
                 │
                 ▼
          HTTP Request + JWT
                 │
                 ▼
        ASP.NET Core Web API
                 │
       Authentication
                 │
       Authorization
                 │
                 ▼
         Protected Resource

You need security at the backend.


Angular Side

For example:

export const adminGuard: CanActivateFn = () => {

  const authService = inject(AuthService);
  const router = inject(Router);

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

  return router.createUrlTree(['/access-denied']);
};

This improves the application's UI behavior.


ASP.NET Core Side

The API must independently enforce authorization.

For authentication:

[Authorize]
[HttpGet("profile")]
public IActionResult GetProfile()
{
    return Ok();
}

For Admin-only access:

[Authorize(Roles = "Admin")]
[HttpGet("users")]
public IActionResult GetUsers()
{
    return Ok();
}

Now even if someone bypasses Angular:

Direct API request
       ↓
/api/admin/users
       ↓
ASP.NET Core
       ↓
[Authorize(Roles = "Admin")]
       ↓
Check authenticated identity + claims
       ↓
Authorized?
    /        \
  Yes         No
   ↓           ↓
200 OK     401 / 403

The backend is the actual enforcement point.


Angular Guard vs ASP.NET Core Authorization

Angular Route Guard ASP.NET Core Authorization
Runs in browser Runs on server
Controls Angular navigation Controls access to API/resources
Improves UX Enforces security
Can prevent opening protected UI routes Can prevent unauthorized API calls
Can be bypassed by direct API requests Cannot be bypassed merely by bypassing Angular
Example: CanActivateFn Example: [Authorize]

What About JWT?

In a typical setup:

Login
  ↓
Angular sends credentials
  ↓
ASP.NET Core validates user
  ↓
JWT issued
  ↓
Angular sends JWT with API requests
  ↓
ASP.NET Core validates JWT
  ↓
Authentication established
  ↓
Authorization checks claims/roles

For example:

JWT
 ├── UserId
 ├── Name
 └── Role = Admin

Angular might use authentication state to decide whether to display:

Admin menu
Admin page
Admin buttons

But ASP.NET Core must still verify the authenticated user's permissions before returning protected data or performing protected operations.


Authentication vs Authorization Failure

Another useful interview point:

401 Unauthorized

Usually means:

The request is not successfully authenticated.

For example:

No JWT
Invalid JWT
Expired JWT

403 Forbidden

Usually means:

The user is authenticated, but does not have permission.

For example:

Authenticated
Role = User

Endpoint requires:
Role = Admin

→ 403 Forbidden

Easy memory:

401
 ↓
Who are you?


403
 ↓
I know who you are,
but you're not allowed.

Key Points

  • Use a route guard such as CanActivateFn to redirect unauthenticated users.
  • A common redirect is:
return router.createUrlTree(['/login']);
  • state.url can preserve the original requested URL for post-login navigation.
  • Angular guards control client-side routing.
  • Angular guards alone are not sufficient security.
  • Never rely solely on Angular for authorization.
  • ASP.NET Core must independently authenticate and authorize API requests.
  • Use backend mechanisms such as:
[Authorize]

or:

[Authorize(Roles = "Admin")]
  • Think of it as:
Angular Guard
     ↓
Navigation / UX


ASP.NET Core Authorization
     ↓
Security / Enforcement

Interview Questions and Answers

1. How do you redirect an unauthenticated user to Login?

Use an authentication guard and return a redirect:

if (!authService.isLoggedIn()) {
  return router.createUrlTree(['/login']);
}

return true;

2. Why use createUrlTree() instead of router.navigate() inside a guard?

Returning a UrlTree expresses the redirect as the guard's navigation result instead of manually triggering another navigation.


3. Can Angular route guards provide real security?

No. Route guards control client-side navigation. Backend APIs must independently enforce authentication and authorization.


4. Why can Angular guards be bypassed?

Because Angular runs on the client. A user can attempt to call backend APIs directly without navigating through the Angular application.


5. Where should actual authorization be performed?

On the backend.

For ASP.NET Core:

[Authorize(Roles = "Admin")]

can enforce Admin access on the server.


6. What is the difference between 401 and 403?

401 generally means authentication is missing or invalid.

403 means the request is authenticated, but the authenticated user doesn't have sufficient permission.


Interview-ready answer

In Angular, an unauthenticated user can be redirected to the login page using a CanActivateFn guard that returns a redirect such as router.createUrlTree(['/login']). However, route guards do not provide backend security because they execute in the browser and can be bypassed by directly calling the API. Therefore, an ASP.NET Core backend must independently enforce authentication and authorization using mechanisms such as [Authorize] and role- or policy-based authorization.