I am trying to make a login system using a typescript/react frontend and a typescript/nodejs backend. Currently, when the user is logged out, my backend returns a 401 (not authorized) error code, since the user isn’t logged in. My issue is that this error code gets automatically logged in the console without me telling it to do so.
So, in the frontend I made a HttpService, which I am using:
<code>import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource } from "axios";
import { useNavigate } from "react-router-dom";
[key: string]: string | number | boolean;
type RequestResult<T> = {
request: Promise<AxiosResponse<T>>;
private instance: AxiosInstance;
constructor(baseURL: string = "http://localhost:3001") {
this.instance = axios.create({ baseURL: this.baseUrl, withCredentials: true });
private get defaultHeaders(): CustomHeaders {
Authorization: localStorage.getItem("Authorization") || "",
"Content-Type": "application/json",
private async request<T>(
method: "get" | "post" | "put" | "delete",
customHeaders: CustomHeaders = {}
): Promise<RequestResult<T>> {
const headers = { ...this.defaultHeaders, ...customHeaders };
const source: CancelTokenSource = axios.CancelToken.source();
const config: AxiosRequestConfig = {
cancelToken: source.token,
request: this.instance.request<T>(config),
public get<T>(url: string, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("get", url, null, customHeaders);
public post<T>(url: string, data: any, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("post", url, data, customHeaders);
public put<T>(url: string, data: any, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("put", url, data, customHeaders);
public delete<T>(url: string, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("delete", url, null, customHeaders);
export default HttpService;
<code>import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource } from "axios";
import { useNavigate } from "react-router-dom";
type CustomHeaders = {
[key: string]: string | number | boolean;
};
type RequestResult<T> = {
request: Promise<AxiosResponse<T>>;
cancel: () => void;
};
class HttpService {
private baseUrl: string;
private instance: AxiosInstance;
constructor(baseURL: string = "http://localhost:3001") {
this.baseUrl = baseURL;
this.instance = axios.create({ baseURL: this.baseUrl, withCredentials: true });
}
private get defaultHeaders(): CustomHeaders {
return {
Authorization: localStorage.getItem("Authorization") || "",
"Content-Type": "application/json",
};
}
private async request<T>(
method: "get" | "post" | "put" | "delete",
url: string,
data: any = null,
customHeaders: CustomHeaders = {}
): Promise<RequestResult<T>> {
const headers = { ...this.defaultHeaders, ...customHeaders };
const source: CancelTokenSource = axios.CancelToken.source();
const config: AxiosRequestConfig = {
method,
url,
headers,
cancelToken: source.token,
};
if (data) {
config.data = data;
}
return {
request: this.instance.request<T>(config),
cancel: source.cancel,
};
}
public get<T>(url: string, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("get", url, null, customHeaders);
}
public post<T>(url: string, data: any, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("post", url, data, customHeaders);
}
public put<T>(url: string, data: any, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("put", url, data, customHeaders);
}
public delete<T>(url: string, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("delete", url, null, customHeaders);
}
}
export default HttpService;
</code>
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource } from "axios";
import { useNavigate } from "react-router-dom";
type CustomHeaders = {
[key: string]: string | number | boolean;
};
type RequestResult<T> = {
request: Promise<AxiosResponse<T>>;
cancel: () => void;
};
class HttpService {
private baseUrl: string;
private instance: AxiosInstance;
constructor(baseURL: string = "http://localhost:3001") {
this.baseUrl = baseURL;
this.instance = axios.create({ baseURL: this.baseUrl, withCredentials: true });
}
private get defaultHeaders(): CustomHeaders {
return {
Authorization: localStorage.getItem("Authorization") || "",
"Content-Type": "application/json",
};
}
private async request<T>(
method: "get" | "post" | "put" | "delete",
url: string,
data: any = null,
customHeaders: CustomHeaders = {}
): Promise<RequestResult<T>> {
const headers = { ...this.defaultHeaders, ...customHeaders };
const source: CancelTokenSource = axios.CancelToken.source();
const config: AxiosRequestConfig = {
method,
url,
headers,
cancelToken: source.token,
};
if (data) {
config.data = data;
}
return {
request: this.instance.request<T>(config),
cancel: source.cancel,
};
}
public get<T>(url: string, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("get", url, null, customHeaders);
}
public post<T>(url: string, data: any, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("post", url, data, customHeaders);
}
public put<T>(url: string, data: any, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("put", url, data, customHeaders);
}
public delete<T>(url: string, customHeaders: CustomHeaders = {}): Promise<RequestResult<T>> {
return this.request<T>("delete", url, null, customHeaders);
}
}
export default HttpService;
Before I get to the next part of the code, I want to explain that this line, which is from the code above, is where the unwanted error log happens:
request: this.instance.request<T>(config),
And this is the code snippet that uses the httpService to check if the user is logged in:
const checkUserLoggedIn = async () => {
const { request } = await httpService.get("/api/v1/user/checkAuth");
const res: any = await request;
<code>useEffect(() => {
const checkUserLoggedIn = async () => {
try {
const { request } = await httpService.get("/api/v1/user/checkAuth");
const res: any = await request;
setUser(res.data.user);
} catch (err: any) {
setUser(null);
} finally {
setIsLoading(false);
}
};
checkUserLoggedIn();
}, []);
</code>
useEffect(() => {
const checkUserLoggedIn = async () => {
try {
const { request } = await httpService.get("/api/v1/user/checkAuth");
const res: any = await request;
setUser(res.data.user);
} catch (err: any) {
setUser(null);
} finally {
setIsLoading(false);
}
};
checkUserLoggedIn();
}, []);
Now the important part from the backend:
<code>const authMiddleware = async (req: Request, res: Response, next: NextFunction) => {
const refreshToken = req.cookies.refresh_token;
const accessToken = req.cookies.access_token;
if (!refreshToken && !accessToken) {
return res.status(401).json({ message: "Access denied. No token provided." });
//more validation would be after this
<code>const authMiddleware = async (req: Request, res: Response, next: NextFunction) => {
const refreshToken = req.cookies.refresh_token;
const accessToken = req.cookies.access_token;
if (!refreshToken && !accessToken) {
clearTokenCookies(res);
return res.status(401).json({ message: "Access denied. No token provided." });
}
//more validation would be after this
}
</code>
const authMiddleware = async (req: Request, res: Response, next: NextFunction) => {
const refreshToken = req.cookies.refresh_token;
const accessToken = req.cookies.access_token;
if (!refreshToken && !accessToken) {
clearTokenCookies(res);
return res.status(401).json({ message: "Access denied. No token provided." });
}
//more validation would be after this
}
This is a middleware I already implemented for some other functions to check if the user is allowed to send a request, I just used it for the checkAuth endpoint as well.
So, this is the exact log in the console in the frontend that I do not want:
GET http://localhost:3001/api/v1/user/checkAuth 401 (Unauthorized)
dispatchXhrRequest @ xhr.js:195
dispatchRequest @ dispatchRequest.js:51
request @ HttpService.ts:51
checkUserLoggedIn @ AuthProvider.tsx:28
(anonymous) @ AuthProvider.tsx:38
commitHookEffectListMount @ react-dom.development.js:23189
commitPassiveMountOnFiber @ react-dom.development.js:24965
commitPassiveMountEffects_complete @ react-dom.development.js:24930
commitPassiveMountEffects_begin @ react-dom.development.js:24917
commitPassiveMountEffects @ react-dom.development.js:24905
flushPassiveEffectsImpl @ react-dom.development.js:27078
flushPassiveEffects @ react-dom.development.js:27023
(anonymous) @ react-dom.development.js:26808
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
<code>HttpService.ts:51
GET http://localhost:3001/api/v1/user/checkAuth 401 (Unauthorized)
dispatchXhrRequest @ xhr.js:195
xhr @ xhr.js:15
dispatchRequest @ dispatchRequest.js:51
_request @ Axios.js:173
request @ Axios.js:40
wrap @ bind.js:5
request @ HttpService.ts:51
get @ HttpService.ts:57
checkUserLoggedIn @ AuthProvider.tsx:28
(anonymous) @ AuthProvider.tsx:38
commitHookEffectListMount @ react-dom.development.js:23189
commitPassiveMountOnFiber @ react-dom.development.js:24965
commitPassiveMountEffects_complete @ react-dom.development.js:24930
commitPassiveMountEffects_begin @ react-dom.development.js:24917
commitPassiveMountEffects @ react-dom.development.js:24905
flushPassiveEffectsImpl @ react-dom.development.js:27078
flushPassiveEffects @ react-dom.development.js:27023
(anonymous) @ react-dom.development.js:26808
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
</code>
HttpService.ts:51
GET http://localhost:3001/api/v1/user/checkAuth 401 (Unauthorized)
dispatchXhrRequest @ xhr.js:195
xhr @ xhr.js:15
dispatchRequest @ dispatchRequest.js:51
_request @ Axios.js:173
request @ Axios.js:40
wrap @ bind.js:5
request @ HttpService.ts:51
get @ HttpService.ts:57
checkUserLoggedIn @ AuthProvider.tsx:28
(anonymous) @ AuthProvider.tsx:38
commitHookEffectListMount @ react-dom.development.js:23189
commitPassiveMountOnFiber @ react-dom.development.js:24965
commitPassiveMountEffects_complete @ react-dom.development.js:24930
commitPassiveMountEffects_begin @ react-dom.development.js:24917
commitPassiveMountEffects @ react-dom.development.js:24905
flushPassiveEffectsImpl @ react-dom.development.js:27078
flushPassiveEffects @ react-dom.development.js:27023
(anonymous) @ react-dom.development.js:26808
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
So, I have been trying to find solutions for a few hours now, but I got nothing, however I have tried some different things.
First was adding an axios interceptor, however that did not fix the auto logging issue, same with a try/catch block.
I have slowly been able to gather that this is a default XHR behavior, and may even be something you do not want to “fix”? But I am not sure.
One way I found to at least remove the error was adding to my constructor:
<code>XMLHttpRequest.prototype.open = function () {
this.addEventListener("error", function (event) {
console.log("error", event);
this.addEventListener("load", function (event) {
console.log("load", event);
<code>XMLHttpRequest.prototype.open = function () {
this.addEventListener("error", function (event) {
event.preventDefault();
console.log("error", event);
});
this.addEventListener("load", function (event) {
console.log("load", event);
});
};
</code>
XMLHttpRequest.prototype.open = function () {
this.addEventListener("error", function (event) {
event.preventDefault();
console.log("error", event);
});
this.addEventListener("load", function (event) {
console.log("load", event);
});
};
However, this also did not properly work. (and would probably break some kind of other code)
So now, I am stumped. I do not know how to solve this, or even IF I should solve this? Should I just send my errors differently? Like for example just sending res.status(200).json({loggedIn: false})
or something like that?
Has anyone ever dealt with this before? If so, I would be very thankful for your response! I will of course update my question if I have missed anything or not specified anything well enough.