JWT Authentication
HTTP Interceptor
- Create a http interceptor to add token to all outgoing http requests
- Create a service
- with VS Code extension (OR)
- with
ng generate service token-interceptor
- Implement
HttpInterceptor
interface - Implement
inercept()
method
- Create a service
- Add
Authorization
header to outgoing request - If response results in
401 Unauthorized
error, redirect to login page
token-interceptor-service.ts
export class TokenInterceptorService implements HttpInterceptor {
constructor(private authService: AuthService, private router: Router) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
// req.headers.append('Authorization', `Bearer ${this.authService.getToken()}`);
req = req.clone({
setHeaders: {
Authorization: `Bearer ${this.authService.getToken()}`,
},
});
return next.handle(req).pipe(
catchError(error => {
if (error instanceof HttpErrorResponse && error.status === 401) {
return this.handle410Error(req, next, error);
} else {
return throwError(error);
}
})
);
}
private handle410Error(req: HttpRequest<any>, next: HttpHandler, error) {
this.router.navigate(['/login']);
// return next.handle(req);
return throwError(error);
}
}
- Register Interceptor at
AppModule
app.module.ts
providers: [
{
provide : HTTP_INTERCEPTORS,
useClass : TokenInterceptorService,
multi : true
}
],
Auth Guard
- Create Auth Guard to protect private routes
- Create a service
- with VS Code extension (OR)
- with
ng generate service auth-guard
- Implement
CanActivate
interface - Implement
canActivate()
method
- Create a service
- If there is no token redirect to login
auth-guard-service.ts
export class AuthGuardService implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean {
let token = this.authService.getToken();
if(token === null){
this.router.navigate(['/login'])
return false;
}else{
return true;
}
}
}
Router Module
- Add
canActivate
property to private routes inRouterModule
app.routing.module.ts
const routes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'login'
},
{
path: 'login',
component: LoginComponent,
},
{
path: 'home',
component: HomeComponent,
canActivate: [AuthGuardService]
}
];
Auth Service
- Create Auth Service to manage token, login and logout
- Create a service
- with VS Code extension (OR)
- with
ng generate service auth-guard
- Create a service
auth.service.ts
export class AuthService {
constructor(private httpClient: HttpClient, private router: Router) {}
verifyToken(): Observable<any> {
return this.httpClient.get(`${environment.api_url}/safe/verify`);
}
login(email, password): Observable<any> {
return this.httpClient.post(`${environment.api_url}/api/user/login`, {
email: email,
password: password,
});
}
logout(): void {
localStorage.removeItem('token');
this.router.navigate(['/login']);
}
getToken(): string {
return localStorage.getItem('token');
}
setToken(token): void {
localStorage.setItem('token', token);
}
}
Login Component
login.component.html
<div>
<input type="text" name="email" id="email" #emailRef />
<input type="password" name="password" id="password" #passwordRef />
<button type="submit" (click)="login(emailRef.value, passwordRef.value)">Login</button>
</div>
- On
ngOnInit()
verify token and if it is valid, redirect to home - On
login()
method if token is received from service on successful login, redirect to home
login.component.ts
constructor(private authService: AuthService, private router: Router) {}
ngOnInit() {
this.authService.verifyToken().subscribe((data) => {
if (data.user !== null) {
this.router.navigate(['/home']);
}
});
}
login(email, password) {
this.authService.login(email, password).subscribe((data) => {
if (data.token !== null) {
this.authService.setToken(data.token);
this.router.navigate(['/home']);
}
});
}
Logout
home.component.html
<button (click)="logout()">Logout</button>
home.component.ts
logout() {
this.authService.logout();
}