Angular sometime fails to add XSRF token, so we added interceptor do double check and add token when missing. Then we found it is failing to read cookie sometimes, so we added 3rd party library to read cookies.. but we are still facing prod errors where XSRF token is missing on 1st attempt, especially when there is redirect from another site to our side, subsequent refresh of page is working fine.
One of our theories is that cookies are not yet set i.e. a race condition where angular read of cookies is running way before cookies are actually set.. thought amount traffic hitting this error is low, we need to address those errors and reduce customer frustration.
Now we would like to hold requests for few milliseconds then read cookies, even then if cookies are not found, we would like to perform a 2nd /ws/bootstrap call.
I am having hard time to understand or come up with a code inside this interceptor. Any suggestions or references are much appreciated.
Meanwhile I will try to post my modified code in comments, but that's pretty much non working code as of now.
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpXsrfTokenExtractor } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ILoggerInstance, LoggerService } from '@foo/logger-angular';
import { CookieService } from 'ngx-cookie-service';
import { Observable } from 'rxjs';
// Angular adds XSRF header only for Post, below code adds for all GET (i.e. any halHttp call)
// https://github.com/angular/angular/issues/20511
@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {
private readonly log: ILoggerInstance;
private readonly xsrfHeaderName = 'X-XSRF-TOKEN';
private readonly xsrfCookieName = 'XSRF-TOKEN';
constructor(
private readonly tokenExtractor: HttpXsrfTokenExtractor,
private readonly cookieService: CookieService,
private readonly logger: LoggerService
) {
this.log = this.logger.getInstance('HttpXsrfInterceptor');
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!req.headers.has(this.xsrfHeaderName)) {
// We have seen header missing in prod for approx 10% traffic, so adding non angular way of retrieving cookie if angular failed for some reason.
const token = this.tokenExtractor.getToken() || this.cookieService.get(this.xsrfCookieName);
if (token) {
req = req.clone({ headers: req.headers.set(this.xsrfHeaderName, token) });
} else if (req.url !== 'ws/bootstrap' && req.url !== 'bootstrap') {
// Exclude bootstrap it issues xsrf cookie
this.log.error('Missing xsrf cookie');
}
}
return next.handle(req);
}
}