In today's web applications, staying logged in on a website for an extended period, whether an hour or two, can pose security risks. During this time, background API calls might still be running, and if you're not actively using the site, someone else could potentially access it with your credentials. To mitigate these risks and reduce unnecessary server requests, it's crucial to monitor user activity, such as cursor movement or key presses. If the system detects inactivity for a specified duration, it can automatically log the user out. This feature, known as Idle Timeout, is essential for modern web applications.
Let’s dive into implementing idle timeout in Angular.
idleService.ts
import { Injectable } from '@angular/core';
import { interval, Observable, Subject, Subscription, throttle } from 'rxjs';
export class IdleService {
private idleSubject = new Subject<boolean>();
private timeout = 1200; //seconds
private lastActivity?: Date;
private idleCheckInterval = 600; //seconds
private idleSubscription?: Subscription
constructor() {
this.resetTimer();
this.startWatching();
}
get idleState(): Observable<boolean> {
return this.idleSubject.asObservable();
}
private startWatching(): void {
this.idleSubscription = interval(this.idleCheckInterval * 1000)
.pipe(throttle(() => interval(1000)))
.subscribe(() => {
const now = new Date();
if (now.getTime() - this.lastActivity?.getTime()! > this.timeout * 1000) {
this.idleSubject.next(true);
}
});
}
resetTimer(): void {
this.lastActivity = new Date();
this.idleSubject.next(false);
}
stopWatching(): void {
if (this.idleSubscription) {
this.idleSubscription.unsubscribe();
}
}
}
This service monitors user activity and checks if the user has been idle for a specified duration. If so, it triggers an event through idleSubject
app.component.ts
import { inject, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { IdleService } from 'path-to-your-idleService';
export class AppComponent implements OnInit, OnDestroy {
private idleSubscription?: Subscription;
private idleService = inject(IdleService);
ngOnInit(): void {
this.idleSubscription = this.idleService.idleState.subscribe((isIdle) => {
if (isIdle) {
console.log("user is idle");
// Add logic for handling idle state, e.g., logging out
} else {
console.log("user is active");
}
});
}
onUserAction(): void {
this.idleService.resetTimer();
}
ngOnDestroy(): void {
if (this.idleSubscription) {
this.idleSubscription.unsubscribe();
}
}
Subscribes to the idle state and handles the user being idle or active. It also resets the idle timer on user interactions such as mouse movements, clicks, or key presses.
app.component.html
<div
(mousemove)="onUserAction()"
(click)="onUserAction()"
(keypress)="onUserAction()"
>
<router-outlet />
</div>
Captures user interactions to reset the idle timer whenever activity is detected.