1. What is Authentication?
Authentication answers this question: “Who are you?”
Authorization answers another question: “What are you allowed to do?”
Authentication
The user logs in with email, password, Google login, phone OTP, or another identity method.
Authorization
The app checks whether the logged-in user is allowed to open a page or perform an action.
| Term | Meaning | Angular Example |
|---|---|---|
| Login | User proves identity. | Email and password form. |
| Token | A small proof returned by server after login. | JWT (JSON Web Token). |
| Guard | Protects routes from unauthorized access. | canActivate guard. |
| Interceptor | Adds token to HTTP requests automatically. | Authorization: Bearer token. |
| Role | User category or permission level. | admin, student, teacher. |
2. Angular Setup
Create a fresh Angular project.
npm install -g @angular/cli
ng new angular-auth-demo
cd angular-auth-demo
ng serve
ng serve. Open http://localhost:4200.
You should see the Angular application running.
Open the project in Visual Studio Code.
code .
src/app/app.component.ts,
src/app/app.component.html,
src/app/app.routes.ts,
src/app/app.config.ts.
3. The Authentication Flow
A common Angular authentication flow looks like this:
- User opens the login page.
- User enters email and password.
- Angular sends the login data to the backend API.
- Backend verifies the credentials.
- Backend returns a token and user information.
- Angular stores the token.
- Angular uses a guard to protect private pages.
- Angular uses an interceptor to attach the token to future API requests.
- User logs out and Angular removes the token.
4. Fake Login First
A fake login does not call a real server. It checks one email and password locally. This is not real security, but it teaches the Angular flow clearly.
Email: student@example.com
Password: 123456
We will create:
AuthServicefor login, logout, and checking login status.LoginComponentfor the login form.DashboardComponentas a protected page.AuthGuardto stop direct access to dashboard.
5. Create Auth Service
A service is the best place to keep authentication logic.
ng generate service services/auth
src/app/services/auth.service.ts
import { Injectable } from '@angular/core';
export interface LoginRequest {
email: string;
password: string;
}
export interface AuthUser {
email: string;
name: string;
role: 'student' | 'teacher' | 'admin';
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
private tokenKey = 'pp_auth_token';
private userKey = 'pp_auth_user';
login(credentials: LoginRequest): boolean {
if (
credentials.email === 'student@example.com' &&
credentials.password === '123456'
) {
const fakeToken = 'fake-jwt-token-for-learning';
const user: AuthUser = {
email: credentials.email,
name: 'Student User',
role: 'student'
};
localStorage.setItem(this.tokenKey, fakeToken);
localStorage.setItem(this.userKey, JSON.stringify(user));
return true;
}
return false;
}
logout(): void {
localStorage.removeItem(this.tokenKey);
localStorage.removeItem(this.userKey);
}
isLoggedIn(): boolean {
return !!localStorage.getItem(this.tokenKey);
}
getToken(): string | null {
return localStorage.getItem(this.tokenKey);
}
getUser(): AuthUser | null {
const userJson = localStorage.getItem(this.userKey);
if (!userJson) {
return null;
}
return JSON.parse(userJson) as AuthUser;
}
getRole(): string | null {
return this.getUser()?.role || null;
}
}
6. Create Login Component
ng generate component pages/login
ng generate component pages/dashboard
ng generate component pages/home
src/app/pages/login,
src/app/pages/dashboard,
src/app/pages/home.
Login Component Logic
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Router, RouterLink } from '@angular/router';
import { AuthService, LoginRequest } from '../../services/auth.service';
@Component({
selector: 'app-login',
imports: [FormsModule, RouterLink],
templateUrl: './login.component.html',
styleUrl: './login.component.css'
})
export class LoginComponent {
credentials: LoginRequest = {
email: '',
password: ''
};
errorMessage = '';
constructor(
private authService: AuthService,
private router: Router
) {}
login() {
this.errorMessage = '';
const success = this.authService.login(this.credentials);
if (success) {
this.router.navigate(['/dashboard']);
} else {
this.errorMessage = 'Invalid email or password.';
}
}
}
Login Component HTML
<main class="auth-page">
<section class="auth-card">
<h1>Login</h1>
<p>Use the demo account to enter the dashboard.</p>
<div class="demo-box">
<strong>Demo Email:</strong> student@example.com<br />
<strong>Demo Password:</strong> 123456
</div>
<form (ngSubmit)="login()">
<label>
Email
<input
type="email"
name="email"
[(ngModel)]="credentials.email"
required
placeholder="student@example.com"
/>
</label>
<label>
Password
<input
type="password"
name="password"
[(ngModel)]="credentials.password"
required
placeholder="123456"
/>
</label>
@if (errorMessage) {
<p class="error">{{ errorMessage }}</p>
}
<button type="submit">Login</button>
</form>
<p>
<a routerLink="/">Back to home</a>
</p>
</section>
</main>
Login Component CSS
.auth-page {
min-height: 100vh;
display: grid;
place-items: center;
background: #fff7ed;
padding: 24px;
}
.auth-card {
width: min(460px, 100%);
background: white;
border-radius: 24px;
padding: 28px;
box-shadow: 0 18px 40px rgba(100, 50, 0, 0.14);
border: 1px solid #ffd0a1;
}
h1 {
margin-top: 0;
color: #9a3412;
}
label {
display: block;
margin: 16px 0;
font-weight: bold;
}
input {
display: block;
width: 100%;
margin-top: 8px;
padding: 13px;
border-radius: 12px;
border: 1px solid #d6b17d;
font-size: 16px;
}
button {
width: 100%;
padding: 13px;
border: none;
border-radius: 999px;
background: #ff9933;
color: #1f1300;
font-weight: bold;
cursor: pointer;
font-size: 16px;
}
.demo-box {
background: #fff3e3;
padding: 14px;
border-radius: 14px;
border: 1px solid #ffd0a1;
}
.error {
color: white;
background: #b91c1c;
padding: 10px;
border-radius: 10px;
}
7. Set Up Routing
Routing decides which component appears for which URL.
import { Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';
import { LoginComponent } from './pages/login/login.component';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
export const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'login',
component: LoginComponent
},
{
path: 'dashboard',
component: DashboardComponent
},
{
path: '**',
redirectTo: ''
}
];
App Component HTML
<router-outlet></router-outlet>
App Component TypeScript
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {}
http://localhost:4200/login. You should see the login page.
Open http://localhost:4200/dashboard. At this stage, it will still open because the
guard is not added yet.
8. Protect Routes with an Auth Guard
A guard prevents unauthorized users from entering protected pages.
ng generate guard guards/auth
src/app/guards
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isLoggedIn()) {
return true;
}
return router.createUrlTree(['/login']);
};
Add Guard to Dashboard Route
import { Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';
import { LoginComponent } from './pages/login/login.component';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
import { authGuard } from './guards/auth.guard';
export const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'login',
component: LoginComponent
},
{
path: 'dashboard',
component: DashboardComponent,
canActivate: [authGuard]
},
{
path: '**',
redirectTo: ''
}
];
http://localhost:4200/dashboard without logging in.
You should be redirected to /login.
9. Dashboard and Logout
After login, the user should see a private page and a logout button.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService, AuthUser } from '../../services/auth.service';
@Component({
selector: 'app-dashboard',
imports: [],
templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.css'
})
export class DashboardComponent {
user: AuthUser | null = null;
constructor(
private authService: AuthService,
private router: Router
) {
this.user = this.authService.getUser();
}
logout() {
this.authService.logout();
this.router.navigate(['/login']);
}
}
<main class="dashboard">
<nav class="topbar">
<strong>Private Dashboard</strong>
<button (click)="logout()">Logout</button>
</nav>
<section class="card">
<h1>Welcome, {{ user?.name }}</h1>
<p>Email: {{ user?.email }}</p>
<p>Role: {{ user?.role }}</p>
</section>
</main>
.dashboard {
min-height: 100vh;
background: #fff7ed;
padding: 24px;
font-family: Arial, sans-serif;
}
.topbar {
display: flex;
justify-content: space-between;
align-items: center;
background: #2a1704;
color: white;
padding: 16px 20px;
border-radius: 18px;
}
button {
border: none;
border-radius: 999px;
padding: 10px 16px;
background: #ff9933;
color: #1f1300;
font-weight: bold;
cursor: pointer;
}
.card {
margin-top: 24px;
background: white;
border-radius: 24px;
padding: 28px;
border: 1px solid #ffd0a1;
box-shadow: 0 18px 40px rgba(100, 50, 0, 0.12);
}
student@example.com and 123456.
You should reach the dashboard. Click logout. You should return to the login page.
10. JWT: JSON Web Token
JWT means JSON Web Token. A JWT is a compact token usually returned by the backend after successful login.
A JWT has three parts:
header.payload.signature
Header
Information about token type and signing algorithm.
Payload
User-related claims such as id, email, role, and expiry time.
Signature
Server-side proof that the token was not changed.
Example Decoding Function for Learning
export function decodeJwtPayload(token: string): any {
const parts = token.split('.');
if (parts.length !== 3) {
return null;
}
const payload = parts[1];
const decodedPayload = atob(payload);
return JSON.parse(decodedPayload);
}
11. Real API Login Pattern
In a real app, login is usually an HTTP POST request.
Enable HttpClient
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient()
]
};
Auth Models
export interface LoginRequest {
email: string;
password: string;
}
export interface LoginResponse {
token: string;
user: {
id: number;
name: string;
email: string;
role: 'student' | 'teacher' | 'admin';
};
}
Real API Auth Service Pattern
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { tap } from 'rxjs';
import { LoginRequest, LoginResponse } from '../models/auth.models';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private apiUrl = 'https://example.com/api/auth';
private tokenKey = 'pp_auth_token';
private userKey = 'pp_auth_user';
constructor(private http: HttpClient) {}
login(credentials: LoginRequest) {
return this.http
.post<LoginResponse>(`${this.apiUrl}/login`, credentials)
.pipe(
tap(response => {
localStorage.setItem(this.tokenKey, response.token);
localStorage.setItem(this.userKey, JSON.stringify(response.user));
})
);
}
logout() {
localStorage.removeItem(this.tokenKey);
localStorage.removeItem(this.userKey);
}
isLoggedIn(): boolean {
return !!this.getToken();
}
getToken(): string | null {
return localStorage.getItem(this.tokenKey);
}
getUser() {
const userJson = localStorage.getItem(this.userKey);
return userJson ? JSON.parse(userJson) : null;
}
}
Login Component with API
login() {
this.errorMessage = '';
this.authService.login(this.credentials)
.subscribe({
next: () => {
this.router.navigate(['/dashboard']);
},
error: error => {
console.error(error);
this.errorMessage = 'Login failed. Please check your email and password.';
}
});
}
12. Add Token Automatically with an HTTP Interceptor
After login, protected API requests usually need an authorization header.
Authorization: Bearer YOUR_TOKEN_HERE
Instead of manually adding this header everywhere, use an interceptor.
ng generate interceptor interceptors/auth
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';
export const authInterceptor: HttpInterceptorFn = (request, next) => {
const authService = inject(AuthService);
const token = authService.getToken();
if (!token) {
return next(request);
}
const authRequest = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next(authRequest);
};
Register the Interceptor
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
import { authInterceptor } from './interceptors/auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(
withInterceptors([authInterceptor])
)
]
};
Authorization header.
13. Role-Based Access
Sometimes all logged-in users can enter the dashboard, but only admins can enter the admin page.
ng generate component pages/admin
ng generate guard guards/role
Role Guard
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
export const roleGuard: CanActivateFn = (route) => {
const authService = inject(AuthService);
const router = inject(Router);
const allowedRoles = route.data['roles'] as string[];
const currentRole = authService.getRole();
if (currentRole && allowedRoles.includes(currentRole)) {
return true;
}
return router.createUrlTree(['/dashboard']);
};
Route with Role Guard
{
path: 'admin',
component: AdminComponent,
canActivate: [authGuard, roleGuard],
data: {
roles: ['admin']
}
}
14. Refresh Token Idea
Many production systems use two tokens:
Access Token
Short-lived token used to access protected API routes.
Refresh Token
Longer-lived token used to request a new access token.
A simple production flow:
- User logs in.
- Server returns an access token and a refresh token.
- Angular uses the access token for API requests.
- When the access token expires, Angular asks for a new one using the refresh token.
- If refresh fails, Angular logs the user out.
15. Token Storage: localStorage, sessionStorage, Cookies
Token storage is an important security decision.
| Storage | Advantage | Risk / Limitation |
|---|---|---|
localStorage |
Easy to use. Token survives browser restart. | Accessible by JavaScript, so Cross-Site Scripting can be dangerous. |
sessionStorage |
Clears when tab/session ends. | Still accessible by JavaScript. |
| HTTP-only cookie | Not directly readable by JavaScript. | Needs careful backend setup, SameSite, CSRF protection, and secure cookie settings. |
localStorage is convenient.
For serious production apps, discuss storage strategy with the backend and security requirements.
16. Mini Project: Complete Angular Authentication Demo
This mini project uses fake authentication so it can run without a backend.
Features
- Home page.
- Login page.
- Dashboard page.
- Admin page.
- Fake token storage.
- Route guard.
- Role guard.
- Logout.
- Navbar that changes based on login status.
Step 1: Generate Files
ng generate component pages/home
ng generate component pages/login
ng generate component pages/dashboard
ng generate component pages/admin
ng generate service services/auth
ng generate guard guards/auth
ng generate guard guards/role
Step 2: Auth Service
import { Injectable } from '@angular/core';
export interface LoginRequest {
email: string;
password: string;
}
export interface AuthUser {
email: string;
name: string;
role: 'student' | 'admin';
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
private tokenKey = 'pp_auth_token';
private userKey = 'pp_auth_user';
login(credentials: LoginRequest): boolean {
const users = [
{
email: 'student@example.com',
password: '123456',
name: 'Student User',
role: 'student' as const
},
{
email: 'admin@example.com',
password: 'admin123',
name: 'Admin User',
role: 'admin' as const
}
];
const foundUser = users.find(user =>
user.email === credentials.email &&
user.password === credentials.password
);
if (!foundUser) {
return false;
}
const fakeToken = `fake-token-${foundUser.role}-${Date.now()}`;
const userToStore: AuthUser = {
email: foundUser.email,
name: foundUser.name,
role: foundUser.role
};
localStorage.setItem(this.tokenKey, fakeToken);
localStorage.setItem(this.userKey, JSON.stringify(userToStore));
return true;
}
logout(): void {
localStorage.removeItem(this.tokenKey);
localStorage.removeItem(this.userKey);
}
isLoggedIn(): boolean {
return !!localStorage.getItem(this.tokenKey);
}
getToken(): string | null {
return localStorage.getItem(this.tokenKey);
}
getUser(): AuthUser | null {
const userJson = localStorage.getItem(this.userKey);
return userJson ? JSON.parse(userJson) as AuthUser : null;
}
getRole(): 'student' | 'admin' | null {
return this.getUser()?.role || null;
}
}
Step 3: Guards
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isLoggedIn()) {
return true;
}
return router.createUrlTree(['/login']);
};
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
export const roleGuard: CanActivateFn = (route) => {
const authService = inject(AuthService);
const router = inject(Router);
const allowedRoles = route.data['roles'] as string[];
const role = authService.getRole();
if (role && allowedRoles.includes(role)) {
return true;
}
return router.createUrlTree(['/dashboard']);
};
Step 4: Routes
import { Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';
import { LoginComponent } from './pages/login/login.component';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
import { AdminComponent } from './pages/admin/admin.component';
import { authGuard } from './guards/auth.guard';
import { roleGuard } from './guards/role.guard';
export const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'login',
component: LoginComponent
},
{
path: 'dashboard',
component: DashboardComponent,
canActivate: [authGuard]
},
{
path: 'admin',
component: AdminComponent,
canActivate: [authGuard, roleGuard],
data: {
roles: ['admin']
}
},
{
path: '**',
redirectTo: ''
}
];
Step 5: App Shell with Navbar
import { Component } from '@angular/core';
import { Router, RouterLink, RouterOutlet } from '@angular/router';
import { AuthService } from './services/auth.service';
@Component({
selector: 'app-root',
imports: [RouterOutlet, RouterLink],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {
constructor(
public authService: AuthService,
private router: Router
) {}
logout() {
this.authService.logout();
this.router.navigate(['/login']);
}
}
<nav class="navbar">
<a routerLink="/" class="brand">Angular Auth Demo</a>
<div class="links">
<a routerLink="/">Home</a>
@if (authService.isLoggedIn()) {
<a routerLink="/dashboard">Dashboard</a>
@if (authService.getRole() === 'admin') {
<a routerLink="/admin">Admin</a>
}
<button (click)="logout()">Logout</button>
} @else {
<a routerLink="/login">Login</a>
}
</div>
</nav>
<router-outlet></router-outlet>
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
background: #2a1704;
color: white;
padding: 14px 24px;
font-family: Arial, sans-serif;
}
.brand {
color: #ffd49a;
font-weight: bold;
text-decoration: none;
}
.links {
display: flex;
align-items: center;
gap: 14px;
}
a {
color: white;
text-decoration: none;
font-weight: bold;
}
button {
border: none;
border-radius: 999px;
padding: 9px 14px;
background: #ff9933;
color: #1f1300;
font-weight: bold;
cursor: pointer;
}
@media (max-width: 700px) {
.navbar,
.links {
flex-direction: column;
align-items: flex-start;
}
}
Step 6: Home Page
<main class="page">
<section class="hero">
<h1>Angular Authentication Demo</h1>
<p>Learn login, logout, protected routes, and role-based access.</p>
<div class="cards">
<div class="card">
<h2>Student Login</h2>
<p>Email: student@example.com</p>
<p>Password: 123456</p>
</div>
<div class="card">
<h2>Admin Login</h2>
<p>Email: admin@example.com</p>
<p>Password: admin123</p>
</div>
</div>
</section>
</main>
.page {
min-height: calc(100vh - 60px);
background: #fff7ed;
padding: 32px;
font-family: Arial, sans-serif;
}
.hero {
max-width: 1000px;
margin: auto;
padding: 40px;
border-radius: 28px;
background: linear-gradient(135deg, #ff9933, #ffd6a3);
color: #2a1400;
}
h1 {
font-size: 44px;
margin-top: 0;
}
.cards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
margin-top: 24px;
}
.card {
background: white;
border-radius: 20px;
padding: 20px;
border: 1px solid #ffd0a1;
}
@media (max-width: 700px) {
.cards {
grid-template-columns: 1fr;
}
h1 {
font-size: 32px;
}
}
Step 7: Login Page
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService, LoginRequest } from '../../services/auth.service';
@Component({
selector: 'app-login',
imports: [FormsModule],
templateUrl: './login.component.html',
styleUrl: './login.component.css'
})
export class LoginComponent {
credentials: LoginRequest = {
email: '',
password: ''
};
errorMessage = '';
constructor(
private authService: AuthService,
private router: Router
) {}
login() {
this.errorMessage = '';
const success = this.authService.login(this.credentials);
if (success) {
this.router.navigate(['/dashboard']);
} else {
this.errorMessage = 'Invalid email or password.';
}
}
}
<main class="auth-page">
<section class="auth-card">
<h1>Login</h1>
<form (ngSubmit)="login()">
<label>
Email
<input
type="email"
name="email"
[(ngModel)]="credentials.email"
required
/>
</label>
<label>
Password
<input
type="password"
name="password"
[(ngModel)]="credentials.password"
required
/>
</label>
@if (errorMessage) {
<p class="error">{{ errorMessage }}</p>
}
<button type="submit">Login</button>
</form>
</section>
</main>
.auth-page {
min-height: calc(100vh - 60px);
display: grid;
place-items: center;
background: #fff7ed;
padding: 24px;
font-family: Arial, sans-serif;
}
.auth-card {
width: min(460px, 100%);
background: white;
border-radius: 24px;
padding: 28px;
border: 1px solid #ffd0a1;
box-shadow: 0 18px 40px rgba(100, 50, 0, 0.14);
}
label {
display: block;
margin: 16px 0;
font-weight: bold;
}
input {
display: block;
width: 100%;
margin-top: 8px;
padding: 13px;
border-radius: 12px;
border: 1px solid #d6b17d;
}
button {
width: 100%;
padding: 13px;
border: none;
border-radius: 999px;
background: #ff9933;
color: #1f1300;
font-weight: bold;
cursor: pointer;
}
.error {
color: white;
background: #b91c1c;
padding: 10px;
border-radius: 10px;
}
Step 8: Dashboard Page
import { Component } from '@angular/core';
import { AuthService } from '../../services/auth.service';
@Component({
selector: 'app-dashboard',
imports: [],
templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.css'
})
export class DashboardComponent {
user = this.authService.getUser();
constructor(private authService: AuthService) {}
}
<main class="page">
<section class="card">
<h1>Dashboard</h1>
<p>This is a protected page.</p>
<h2>Logged-in User</h2>
<p>Name: {{ user?.name }}</p>
<p>Email: {{ user?.email }}</p>
<p>Role: {{ user?.role }}</p>
</section>
</main>
.page {
min-height: calc(100vh - 60px);
background: #fff7ed;
padding: 32px;
font-family: Arial, sans-serif;
}
.card {
max-width: 800px;
margin: auto;
background: white;
border-radius: 24px;
padding: 28px;
border: 1px solid #ffd0a1;
box-shadow: 0 18px 40px rgba(100, 50, 0, 0.12);
}
Step 9: Admin Page
<main class="page">
<section class="admin-card">
<h1>Admin Panel</h1>
<p>Only admin users can open this page.</p>
<ul>
<li>Manage users</li>
<li>View reports</li>
<li>Change application settings</li>
</ul>
</section>
</main>
.page {
min-height: calc(100vh - 60px);
background: #fff7ed;
padding: 32px;
font-family: Arial, sans-serif;
}
.admin-card {
max-width: 800px;
margin: auto;
background: white;
border-radius: 24px;
padding: 28px;
border: 1px solid #ffd0a1;
box-shadow: 0 18px 40px rgba(100, 50, 0, 0.12);
}
h1 {
color: #b45309;
}
ng serve. Open http://localhost:4200.
Student login should open dashboard but not admin page.
Admin login should open both dashboard and admin page.
17. Common Mistakes and Fixes
| Mistake | Reason | Fix |
|---|---|---|
Can't bind to ngModel |
FormsModule missing. |
Add imports: [FormsModule] in the component. |
| Dashboard opens without login | Guard not added to route. | Add canActivate: [authGuard]. |
| Page stays logged in after logout | Token was not removed. | Remove token and user from storage in logout(). |
| API says unauthorized | Token not sent in request. | Add an HTTP interceptor to attach the token. |
| Role guard does not work | Route data or user role mismatch. | Check data: { roles: [...] } and stored user role. |
| Frontend guard treated as full security | Misunderstanding of browser apps. | Always enforce security on the backend too. |
18. Practice Tasks
- Create a login page with email and password.
- Create an auth service with login and logout methods.
- Store a fake token after login.
- Show logged-in user details on dashboard.
- Protect dashboard using an auth guard.
- Create an admin page.
- Protect admin page using a role guard.
- Add a navbar that changes after login.
- Add an HTTP interceptor that attaches a token.
- Replace fake login with a real backend API later.
19. Quick Quiz
Final Summary
Angular authentication is not one thing. It is a complete system: login form, auth service, token handling, guards, interceptors, logout, and backend verification.
| Need | Angular Tool |
|---|---|
| Login form | FormsModule and ngModel |
| Store login logic | AuthService |
| Protect pages | CanActivateFn route guard |
| Send token to API | HTTP interceptor |
| Admin-only pages | Role guard |
| End session | logout() and remove token |
| Real security | Backend validation and authorization |
The next natural lesson is: Angular + Backend API Authentication 0 to Infinity.