Angular Authentication: Route Guards.
Samuel Wachira
Posted on October 12, 2023
In the rapidly evolving landscape of web development, crafting secure and user-friendly authentication systems is no longer just a best practice—it's a fundamental necessity. As the migration of applications to the web continues to surge, safeguarding user data privacy and ensuring system integrity have become non-negotiable priorities. In this digital age, where the stakes are higher than ever, developers seek reliable solutions. Angular, with its robust features and versatile framework, emerges as the preferred choice among developers for building dynamic and responsive web applications. However, even within the realm of Angular, implementing a seamless and secure authentication process remains a challenge for many. This comprehensive guide is meticulously designed to unravel the complexities of authentication in Angular, offering a step-by-step journey through the intricate process of securing routes and fortifying your application against potential vulnerabilities.
Step 1: Setting Up Your Angular Application
Begin your journey by ensuring your development environment is finely tuned. Node.js and Angular CLI, your trusty companions in this expedition, must be installed globally. Use the following commands to set the stage for your Angular masterpiece:
npm install -g @angular/cli
Next up, lets create a new Angular application.
ng new my-app
cd my-app
Step 2: Creating Authentication Service
In the heart of your Angular application lies the authentication service. Craft it with care, utilizing the Angular CLI to create a solid foundation:
ng g s auth
After the service is created, open the auth.service.ts file where you can now implment the logic to login, register and the authentication status check. Here is an example of what the service might look like.
import { Injectable } from '@angular/core';
import { User } from '../models/users.model';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
@Injectable({
providedIn: 'root'
})
export class AuthService {
apiUrl: string = 'https://localhost:7023';
constructor(private http: HttpClient) { }
registerUser(newUser: User) : Observable<User>
{
newUser.id = '';
return this.http.post<User>(this.apiUrl + '/api/User/register', newUser);
}
loginUser(username: string, password: string): Observable<any> {
return this.http.post(this.apiUrl + '/api/User/login', { username, password });
}
public isAuthenticated() : boolean {
const token = localStorage.getItem('authToken');
const helper = new JwtHelperService();
const isExpired = helper.isTokenExpired(token);
return !isExpired;
}
}
Step 3: Configuring AuthGuard
Empower your routes with the possibilities of the AuthGuard. In the shared folder of your project, create a AuthGuard.ts file, infusing it with the essence of authentication protection:
import { Injectable } from "@angular/core";
import { Router } from "@angular/router";
import { AuthService } from "../services/auth.service";
@Injectable({
providedIn: 'root'
})
export class AuthGuard {
constructor(private authService: AuthService, private router: Router) {}
canActivate(): boolean {
if (this.authService.isAuthenticated()) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
}
Authentication Check: When a user attempts to access a protected route, the canActivate method in AuthGuard comes into play. It calls the isAuthenticated() method from the AuthService. This method performs authentication logic, determining if the user is logged in or not.
Controlled Access: If the user is authenticated, they are granted access to the requested route. This seamless transition ensures that authenticated users can interact with specific components or features tailored to their authorization level.
Unauthorized Access Handling: If the user is not authenticated, the AuthGuard redirects them to the login page ('/login'). This redirection ensures that unauthorized users cannot bypass the authentication process, maintaining the integrity and security of the application.
Step 4: Setting Up Routes and Navigation
In the app-routing.module.ts
file, configure the routes and create navigation links:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductsComponent } from './products/products.component';
import { LoginComponent } from './components/login/login.component';
import { RegisterComponent } from './components/register/register.component';
import { AuthGuard } from './shared/AuthGuard';
const routes: Routes = [
{ path : "products",component : ProductsComponent,
canActivate: [AuthGuard]
},
{ path: "login",component : LoginComponent },
{ path: "register",component : RegisterComponent },
{ path: "",redirectTo: "products", pathMatch: "full" }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
The code snippet above introduces the concept of a route guard (AuthGuard), a security measure to control access to specific routes. In our configuration, the AuthGuard prevents unauthorized users from accessing the 'products' route. This means that users must be authenticated before they can view the products page, adding an extra layer of security to our application.
By combining routing and guards, our Angular application ensures that users are not only directed to the correct components but are also protected from unauthorized access.
Step 5: Designing the Login Component
Create a login component where users can enter their credentials. Use Angular Reactive Forms for the login form:
// login.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { AuthService } from '../auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {
loginForm: FormGroup;
constructor(private formBuilder: FormBuilder, private authService: AuthService) {
this.loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
}
onSubmit(): void {
const username = this.loginForm.get('username').value;
const password = this.loginForm.get('password').value;
if (this.authService.login(username, password)) {
// Redirect to home page if login successful
} else {
// Display error message for unsuccessful login
}
}
}
Step 6: Adding Logout Functionality
Implement logout functionality in the authentication service:
// handle logout
logout() {
localStorage.removeItem('authToken');
// redirect to login page
window.location.href = '/login';
}
Step 7: User Feedback and Error Handling
Provide feedback to users during login and handle errors gracefully in the login component:
<!-- login.component.html -->
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<input type="text" formControlName="username" placeholder="Username">
<input type="password" formControlName="password" placeholder="Password">
<button type="submit">Login</button>
</form>
<div *ngIf="loginForm.invalid && loginForm.touched" class="error-message">
Please enter valid credentials.
</div>
By following these steps and incorporating the provided code snippets into your Angular application, you'll be able to create a robust and secure authentication system.
Happy Coding! 🚀🔒✨
Posted on October 12, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.