I’m developing an application in react with the backend in c#, for the validation of logged in users, the backend returns me a jwt on login and I save it in the cookies with the security parameters (secure, same-sime: strict, http-only and others), and with each request within the system it kills the previous jwt and creates a new one in a sequential flow, but if I press f5 on the page, it can’t retrieve the jwt because it has the http-only parameter and I end up being kicked from the page. I tried to do some logic using context but I couldn’t solve the page refresh part, I need genuine help.
(I’m currently running the cookie without http-only, so when it refreshes I recover the last saved cookie using the default state value, but I need http-only for pci-dss)
Below is my private route code that wraps my screens (It may seem like dirty code and it really is, but it was the only way to get the user logged in the way they designed the jwt logic):
const PrivateRoute = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(null);
const [token, setToken] = useState(Cookies.get('authToken'));
const [isSessionLoaded, setIsSessionLoaded] = useState(false); // Novo estado
const location = useLocation();
const { userSession, tokenResponse, setTokenResponse, setTokenAtual, tokenAtual, setUserSession } = useAuthContext();
const navigate = useNavigate();
const validation = async () => {
try {
const response = await validateTokenJWT(token);
if (response.data) {
setIsAuthenticated(true);
return response.data;
} else {
Cookies.remove("authToken");
setIsAuthenticated(false);
return navigate("/");
}
} catch (e) {
console.log(e);
return navigate("/");
}
};
const validationFirstTime = async () => {
try {
const response = await validateTokenJWT(tokenResponse);
if (response.data) {
setIsAuthenticated(true);
return response.data;
} else {
Cookies.remove("authToken");
setIsAuthenticated(false);
return navigate("/");
}
} catch (e) {
console.log(e);
return navigate("/");
}
};
useEffect(() => {
const checkToken = async () => {
if (tokenResponse) {
const newToken = await validationFirstTime();
setTokenResponse(null);
if (newToken && newToken !== token) {
setTokenAtual(newToken);
setToken(newToken);
Cookies.set("authToken", newToken, {
expires: new Date(new Date().getTime() + 15 * 60 * 1000),
path: "/",
sameSite: "Strict", // Previne ataques CSRF
secure: true, // Garante que o cookie só seja transmitido via HTTPS
});
systemname.interceptors.request.use(
(config) => {
const token = newToken;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
} else {
Cookies.remove("authToken");
setIsAuthenticated(false);
return navigate("/");
}
} else {
if (token) {
const newToken = await validation();
if (newToken && newToken !== token) {
setTokenAtual(newToken);
setToken(newToken);
Cookies.set("authToken", newToken, {
expires: new Date(new Date().getTime() + 15 * 60 * 1000),
path: "/",
sameSite: "Strict", // Previne ataques CSRF
secure: true, // Garante que o cookie só seja transmitido via HTTPS
});
systemname.interceptors.request.use(
(config) => {
const token = newToken;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
}
} else {
Cookies.remove("authToken");
setIsAuthenticated(false);
return navigate("/");
}
}
};
checkToken();
}, [location.pathname]);
useEffect(() => {
const checkUserSession = async () => {
if (tokenAtual) {
try {
const response = await getUserByAuthToken();
if (response.data) {
setUserSession(response.data);
setIsSessionLoaded(true);
}
} catch (error) {
console.log(error);
}
}
};
checkUserSession();
}, [tokenAtual]);
useEffect(() => {
if (isSessionLoaded) {
const routeName = window.location.pathname.split("/").pop();
const permissions = userSession?.screens;
const permissionFound = permissions.map((screen) => {
if (screen.userScreenId === routeName) {
return true;
} else {
return false;
}
});
const hasPermission = permissionFound.includes(true);
if (!isAuthenticated) {
navigate("/");
} else if (!hasPermission) {
navigate("/AccesDenied");
}
}
}, [isSessionLoaded, userSession, isAuthenticated, navigate]);
if (isAuthenticated === null) {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
}}
>
<Spin size="large" />
</div>
);
}
return children;
};
export default PrivateRoute;
I tried everything, I need help, I’m also looking for some other solution to make this work, even if it means removing the token from the cookie (it would be even better)