- Lab
- Core Tech

Guided: Auth Flow Essentials in Angular
Welcome to the code lab: Guided: Auth Flow Essentials in Angular. This lab is an essential resource for web developers aiming to secure their Angular applications with robust authentication flows and smooth token management. How do you implement user authentication in Angular? How can you protect routes and manage JWTs effortlessly? This Code Lab is designed to help you answer these questions through practical, hands-on learning. A high‑quality web application depends on secure login mechanisms, safe token storage, and guarded navigation. By the end of this Code Lab, you will have the skills to implement login and logout functionality in Angular, attach tokens to HTTP requests via an interceptor, protect routes with an Auth Guard, and manage JWTs securely in browser storage. You’ll be empowered to build scalable, secure, and maintainable Angular applications.

Path Info
Table of Contents
-
Challenge
Introduction and Setup
JWT-based Authentication in Angular
It is crucial to understand how authentication works in modern single-page applications (SPAs) such as Angular.
Traditional web applications relied on server-side
sessions
andcookies
, but SPAs require a different approach because they are stateless and use API-based communication.In your authentication system, you'll implement the JWT (JSON Web Token) pattern, which has become the industry standard for SPA authentication.
When a user successfully logs in, the server generates a JWT containing the user's identity and permissions. This token is then stored on the client side (typically in
localStorage
orsessionStorage
) and sent with every subsequent API request to prove the user's identity.The JWT approach offers several advantages over traditional session-based authentication:
- It is stateless, meaning the server doesn't need to maintain session information, making it highly scalable.
- JWTs are self-contained, carrying all necessary information about the user within the token itself.
- They can be easily shared across different domains and services, making them perfect for microservice architectures.
However, JWT authentication also comes with security considerations like proper token storage, secure transmission, and token expiration handling which are all critical aspects of a robust authentication system.
info> If you get stuck in any of the tasks, you can check the
solutions
folder. #### State ManagementWhen managing authenticated users it is important to validate whether they're still authenticated and whether their token is valid.
The token and login state must be:
- Accessible across components
- Stored safely (in memory,
localStorage
, etc.) - Cleared on logout
You can use Angular services and interceptors to manage authentication state securely and cleanly. #### The Initial Code
In
auth-dashboard
folder you will find a starter application for Angular that was created using the following command:ng new auth-dashboard --routing --style=scss --skip-git --package-manager=npm
The
--routing
flag ensures that Angular Router is configured from the start, which is essential for your multi-page authentication flow.Other important dependencies were installed for the auth API server for JWT, encyrption and cross origin policy which were installed using the following code:
npm install @angular/material @angular/cdk @angular/animations npm install express jsonwebtoken bcryptjs cors npm install --save-dev @types/jsonwebtoken @types/bcryptjs concurrently
The Initial Workspace
Open the project's folder and explore the structure of the workspace including the
auth-dashboard/src/app/app-routes.ts
file which will contain your route definitions and guard configurations, while theapp.ts
will register your services and interceptors.Understanding the Application Goals
This authentication system demonstrates several key concepts:
Security Features:
- JWT token-based authentication with automatic refresh
- Route protection preventing unauthorized access
- HTTP request authentication via interceptors
- Secure routes with authentication guards
User Experience:
- Reactive forms with comprehensive validation
- Loading states and error handling
- Smooth authentication flow with proper redirects
Architecture Patterns:
- Standalone components
- Reactive programming
- Service-based architecture with dependency injection
- Functional guards and interceptors
- Type-safe development with TypeScript
-
Challenge
Building The Login Flow
Reactive Forms in Angular
It is important to understand why you're using Angular's reactive forms approach for our login system.
Reactive forms provide several advantages over template-driven forms, particularly for authentication scenarios where you need precise control over validation, error handling, and form state management.
Reactive forms are built around observable streams, making them inherently compatible with Angular's reactive programming model. This means you can easily combine form validation with HTTP requests, handle loading states, and provide real-time feedback to users.
The reactive approach also makes your forms more testable and maintainable, as the form logic is centralized in the component class rather than scattered across templates. You will find in the
auth-dashboard/src/app/auth
folder, the initial files for authentication service are created using the following command:cd auth-dashboard ng generate service auth/auth
The file
auth-dashbaord/src/app/auth/auth.ts
is then updated to include the functionality for the authentication service including login and JWT validation.You will also find in
auth-dashboard/src/app/components/login
folder, the initial files for the login component generated using the following command:ng generate component components/login ``` ###### Inject AuthService and Wire Up the `.login()` Call To make login work correctly with the authentication service in `auth-dashboard/arc/app/auth/auth.ts/` file, you need to make sure that `AuthService` is injected correctly in the login flow. You inject the `AuthService` by including it to the login component's constructor as shown below: ```ts constructor( ... private authService: AuthService, ... )
The
AuthService
is used in the login component to check if the user is authenticated and to perform login actions.To ensure the app is notified when the user’s state changes, you subscribe to the authentication state using the following code:
ngOnInit(): void { // Subscribe to authentication state changes this.authService.authState$ .pipe(takeUntil(this.destroy$)) .subscribe(state => { this.authState = state; // Redirect to dashboard if already authenticated if (state.isAuthenticated) { this.handlePostLoginRedirect(); } }); ``` #### Reactive Programming with RxJS The authentication service uses `BehaviorSubject` to manage authentication state reactively. This allows components throughout the application to subscribe to authentication changes and respond automatically. #### Form Validation The login component uses Angular's reactive forms to implement robust form validation. It includes: - Required field validation - Minimum/maximum length validation - Real-time error display - User-friendly error messages #### Error Handling The authentication service includes robust error handling that: - Catches HTTP errors and provides user-friendly messages - Updates the authentication state with error details - Allows components to display appropriate error feedback #### Security Considerations - Validate input to prevent malicious values - Prevent open redirect attacks - Secure token storage (`localStorage` for demo; use `httpOnly` cookies in production) - Handle error messages carefully to avoid revealing sensitive information
-
Challenge
Securing HTTP Requests With An Interceptor
An HTTP interceptor in Angular is a centralized place to inspect and modify outgoing HTTP requests and incoming responses. They're especially useful for cross-cutting concerns like:
- Attaching authentication tokens (e.g., JWT) to requests
- Logging or telemetry
- Global error handling
- Retry logic or request deduplication
- Conditionally skipping or transforming requests/responses
Core Idea
Interceptors implement the
HttpInterceptor
interface and sit in the request pipeline. Every outgoingHttpRequest
passes through them before hitting the network, and every incomingHttpResponse
passes back through them.You can generate the initial interceptor code with the following command:
ng generate interceptor auth/auth
Then, update the code to initialize the interceptor and handle unauthorized errors for protected routes.
Open the file
auth-dashboard/src/app/auth/auth.interceptor.ts
and explore the interceptor code. #### Token Refresh StrategyThe interceptor implements a robust token refresh strategy:
- Detects
401 Unauthorized
responses - Automatically attempts to refresh the token
- Queues concurrent requests during refresh
- Retries failed requests with the new token
- Falls back to logout if refresh fails
Request Queuing
If multiple requests fail at the same time because the token has expired, your interceptor queues them and processes them all with the refreshed token, preventing multiple refresh attempts.
Error Handling
The interceptor provides centralized error handling for all HTTP requests and converts technical error messages into user-friendly ones.
-
Challenge
Implementing Logout
Secure Logout Process
The logout implementation follows security best practices:
- Server Notification: Notifies the server for audit logging
- State Cleanup: Clears all authentication state
- Storage Cleanup: Removes tokens from
localStorage
- Navigation: Redirects to login page
- Error Handling: Handles logout failures gracefully
Reactive State Management
The dashboard component subscribes to authentication state changes so it always displays the current user information and responds to logout events.
-
Challenge
Protecting Routes With Auth Guard
Generate an Auth Guard
To restrict access based on user roles, generate an auth guard using the following command:
ng generate guard auth/auth
Explore the customized guard code in the file:
auth-dashboard/src/app/auth/auth.guard.ts
which provides necessary checks over routes to validate if the logged in user had sufficient permissions to access.Role-Based Access Control
The guard supports role-based access control through route data configuration. You can specify required roles for each route, and the guard will check the user's role before allowing access.
Redirect Handling
The guard implements robust redirect handling:
- Stores the intended URL for post-login redirect
- Passes the return URL as a query parameter
- Validates redirect URLs to prevent open redirect attacks
Error Handling
The guard includes comprehensive error handling for authentication failures and provides fallback behavior for edge cases. #### Test Unauthorized Access Behavior
Run the following commands in your terminal:
cd auth-dashboard npm run build node server.js
Then, refresh the browser and sign in using the following credentials of role employee:
username: jdoe password: password
Next, try visiting
localhost:4200/admin
. You should not be allowed access it becausejdoe
doesn’t haveadmin
permissions, the app should keep you on the dashboard page.info> Note: For this lab, the Angular app and mock API run on the same Express server for simplicity. In a production setup, these should run on separate servers, and the Angular app would typically run using
ng serve
. -
Challenge
Validate The Complete Flow
Run the application
info> Note: If you have the app running already skip this part and start going through the validation checklist below.
Run the app using the following commands in the terminal, then refresh your Web Browser:
cd auth-dashboard npm run build node server.js ``` ###### Validation checklist To validate the full authentication and authorization flow, perform the following tests: 1. Try accessing `localhost:4200/dashboard` while logged out * Expected Behavior: You're redirected to the login page. 2. Log in with valid credentials of an employee role (`jdoe` / `password`) and verify dashboard access * Expected Behavior: You should be able to access the dashboard. 3. Log out from the dashboard, then log in with admin credentials (`admin` / `admin123`) and verify admin page access by browsing to `localhost:4200/admin` * Expected Behavior: You should be able to access the admin page. 4. Log out again, then log in with the manager account (`msmith` / `mary2024`) and verify reports page access in `localhost:4200/reports` * Expected Behavior: You should be able to access the reports page 5. Try accessing `localhost:4200/admin` using the manager or employee accounts * Expected Behavior: You should not be able to access the admin page. 6. Log out and verify access is revoked * Expected Behavior: You should be redirected to the login page.
-
Challenge
Wrap‑up And Next Steps
Key Concepts Mastered
Throughout this code lab, you've gained hands-on experience with:
Modern Angular Architecture
- Standalone Components: Eliminated the need for NgModules and embraced Angular's modern component architecture
- Functional Guards and Interceptors: Used the latest Angular patterns for route protection and HTTP request handling
- Reactive Programming: Implemented state management using RxJS observables and
BehaviorSubject
- Dependency Injection: Leveraged Angular's powerful DI system with the new
inject()
function
Authentication and Security
- JWT Token Management: Implemented secure token storage, validation, and automatic refresh
- Route Protection: Created functional guards with role-based access control
- HTTP Security: Built interceptors for automatic token attachment and error handling
- Input Validation: Implemented comprehensive form validation with user-friendly error messages
Further Enhancements
Code Quality
- Enable TypeScript strict mode for better type safety
- Implement comprehensive error handling throughout the application
- Follow Angular style guide and naming conventions
Security
- Never trust client-side data; always validate on the server
- Implement proper input sanitization and output encoding
- Use HTTPS in production and secure cookie attributes
- Regularly update dependencies to patch security vulnerabilities
Performance
- Implement lazy loading for feature modules
- Monitor bundle size and implement code splitting
Maintainability
- Organize code into logical modules and services
- Write comprehensive tests for all critical functionality
- Document complex business logic and architectural decisions
- Implement proper logging and monitoring for production debugging
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.