In the process of creating an authentication application utilizing the PEAN stack (PostgreSQL - ExpressJS - Angular - NodeJS).
To verify the user's sign-in status, the following steps are taken:
- On the backend, the session cookie is checked to determine the existence of the
user
property in thereq.session
object.
server.js
/* ... */
app.post('/api/get-signin-status', async (req, res) => {
try {
if (req.session.user) {
return res.status(200).json({ message: 'User logged in' });
} else {
return res.status(400).json({ message: 'User logged out' });
}
} catch {
return res.status(500).json({ message: 'Internal server error' });
}
});
/* ... */
- Send an HTTP POST request to the
api/get-signin-status
endpoint along with a cookie in the request.
auth.service.ts
/* ... */
getSignInStatus(data?: any) {
return this.http.post(this.authUrl + 'api/get-signin-status', data, {
withCredentials: true,
});
}
/* ... */
- Intercept any HTTP request and provide an observable
interceptorResponse$
for subscribing to the response of intercepted requests.
interceptor.service.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { AuthService } from 'src/app/auth/services/auth.service';
@Injectable({
providedIn: 'root',
})
export class InterceptorService implements HttpInterceptor {
private interceptorResponse$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// code - omitted for brevity
}
getInterceptorResponse(): Observable<any> {
// code - omitted for brevity
}
constructor(private authService: AuthService) {}
}
- On the frontend, subscribe to the
interceptorResponse
observable from theInterceptorService
and log the response to the console.
header.component.ts
import { Component, OnInit } from '@angular/core';
import { InterceptorService } from '../auth/services/interceptor.service';
// code - omitted for brevity
ngOnInit(): void {}
}
Issue
Following guidance from a StackOverflow answer, the use of BehaviorSubject
is recommended. However, the implemented solution returns null instead of the expected updated value. By logging next
and error
, the expected user sign-in status is correctly displayed in the console.
Please refer to the images provided for further visual representation.
Query
Why does the Angular interceptor consistently return null with BehaviorSubject
instead of the updated value?
UPDATE 1
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// additional imports - omitted for brevity
UPDATE 2
The workaround to the quandary was successfully resolved with the assistance of @VonC. The adjustments made are detailed below.
- Elimination of the initial code in
server.js
as the interceptor now relies on theapi/get-user
endpoint, making theapi/get-signin-status
code superfluous. This update ensures that only one endpoint is needed for checking the session cookie, avoiding redundancy.
server.js
/* ... */
/* Removed code */
/* ... */
- Removal of the initial code in
auth.service.ts
and incorporation of the recommended modifications.
auth.service.ts
/* ... */
/* Removed code */
/* Added code */
- Revamp of the original code in
interceptor.service.ts
as advised by @VonC. The endpoint was updated toapi/get-user
for alignment with the backend logic.
interceptor.service.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http';
// additional imports - omitted for brevity
- Modification of the initial code in
header.component.ts
to integrate the proposed changes.
header.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthService } from 'src/app/auth/services/auth.service';
// additional imports - omitted for brevity
ngOnInit(): void {}
}
The integration now allows for the presentation of elements in header.component.html
based on the sign-in status retrieved from the backend.
header.component.html
<div *ngIf="signInStatus">Show this element if the user is signed in</div>
<div *ngIf="!signInStatus">Show this element if the user is signed out</div>