User Authentication and Authorization in angular 16 with JWT

Faruk taiwo
4 min readApr 13, 2024

--

In this article, we delve into the intricacies of user authentication and authorization in Angular 16, focusing specifically on the utilization of JSON Web Tokens (JWT). JWT has become a popular choice for implementing authentication and authorization due to its simplicity, scalability, and interoperability.

Lets dive right into it then.

  1. Authentication Service

The very first service we want to create is an authentication service to handle login, logout, and also token management.

import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export class AuthService {
constructor(private http: HttpClient) {}

isLoggedIn: boolean = false;

login(userDetails: { username: string; password: string }): Observable<boolean> {
return this.http.post<any>('http://examples/api/login', userDetails)
.pipe(
map(response => {
localStorage.setItem('JWT_Token', response.token);
this.isLoggedIn = true;
return true;
}),
catchError(error => {
console.log(error);
this.isLoggedIn = false;
return of(false);
})
);
}

logout(): void {
localStorage.removeItem('JWT_Token');
this.isLoggedIn = false;
}

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

In this service, the login method sends a POST request to the login API endpoint with user credentials, Upon successfully vetting the credentials a success response containing the JWT token is sent back, we then store the JWT in our local storage and update the authentication status. The logout method clears the JWT token from local storage and resets the authentication status. The isAuthenticated method returns whether the user is currently authenticated or Not.

2. Authorization Guard Service

This service ensures secure navigation by restricting access to routes based on user authentication status.

import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
import {inject} from "@angular/core";

export const AuthGuardService : CanActivateFn () => {

let isauthenticated = inject(AuthService).isAuthenticated()
let router = inject(Router)

if (isauthenticated) {
return true;
} else {
router.navigate(['/Login']);
return false;
}
}

By implementing the CanActivateFn, it intercepts route activation attempts. Initially, we define a Function AuthGuardService of type canActivateFn. Next, we assign an instance of the isAuthenticated method from our Authorization service to the variable isauthenticated, and the Router to the variable router. Subsequently, we establish a condition: if isAuthenticated (user is authenticated) it returns true navigation proceeds. otherwise, it returns false, denying user access to the protected route and redirecting them to the ‘login’ page using the router service.

3. Interceptor Service

This Service (JwtInterceptor) intercepts outgoing HTTP requests and adds the JWT to the Authorization header before sending them to the server.

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';

export class JwtInterceptor implements HttpInterceptor {

intercept(req: HttpRequest<any>, next: HttpHandler) {
const token = localStorage.getItem('JWT_Token');
if (token) {
const authReq = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next.handle(authReq);
} else {
return next.handle(req);
}
}
}

We begin by importing essential modules from Angular’s HTTP package. Subsequently, we define a class named JWTInterceptor, which implements the HttpInterceptor interface. Within this class, we define the intercept method, accepting two parameters: req (the HTTP request) and next (the HTTP handler for the next interceptor in the chain).

Retrieving the JWT (JSON Web Token) from the local storage, which was previously stored by our AuthService, is the initial step. We validate the presence of the token, and if it exists, we create a modified copy of the outgoing request (authReq) with an added Authorization header containing the JWT token. This modified request, now including the token, is then forwarded to the server.

Consequently, the server, recognizing the token, grants access to its protected resources. In the case where no token is found, the original request is sent unaltered. Regardless, we ensure the request proceeds to the server by invoking next.handle(request). This interceptor plays a crucial role in augmenting outgoing requests with the necessary authorization credentials, facilitating secure communication with the server.

4. Add our Authorization guard service to our Approuting.module.ts

import { Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { ProductsComponent } from './products.component';
import { AuthGuardService } from './auth-guard.service';

const routes: Routes = [
{ path: 'home', component: HomeComponent, canActivate: [AuthGuardService] },
{ path: 'products', component: ProductsComponent, canActivate: [AuthGuardService] }
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}

Here, we define the routes for our application using the Routes array. Each route is an object with properties defining the path and the component to be displayed when that path is accessed. The canActivate property is used to guard routes, ensuring that certain conditions must be met before allowing access. In this case, AuthGuardService which we earlier created is then imported so that it implements the CanActivate interface to provide route guarding functionality.

5. Provide interceptor in the app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AuthGuardService } from './auth.guard';
import { JwtInterceptor } from './jwt.interceptor';

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule, AppRoutingModule],
providers: [
AuthGuardService,
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule {}

In this Module, we are providing the HeadersInterceptor class as an interceptor using the HTTP_INTERCEPTORS token. The multi: true option ensures that the interceptor is appended to the existing array of interceptors rather than replacing them.

Conclusion

The AuthService manages user login/logout and token storage, while the AuthGuardService ensures secure navigation by restricting access to authenticated users. The JwtInterceptor intercepts outgoing HTTP requests to include the JWT token in the Authorization header. By integrating these components into the application’s routing and module configurations, a robust authentication and authorization system can be established, enhancing security and user experience.

Happy coding!

Well, if you find this quite educative do follow me on linkedin

--

--