Problem sending cookie "connect.sid" with browser - reactjs

I have an ecommerce created with react (front), meanwhile the back is made with express. My session is handled by passport js, and the problem is that I establish the login or the register without any problem, but when I have to re-check the session, the browser (Chrome) never sends back the cookie, so the server is not able to recognize the session. I checked with postman and it works fine. Does someone know why the front does not send the cookie ("connect.sid")???
I leave here the code of the component in react and the code of my router.
import { useContext, useEffect } from "react"
import ItemList from "./ItemList"
import { myContext } from "../contexto/contexto"
import { useHistory } from "react-router"
const ItemListContainer = () => {
const contexto = useContext(myContext)
const history = useHistory()
const obj = {
email: sessionStorage.getItem("user")
}
useEffect(() => {
fetch(`http://localhost:8080/api/usuarios/check-session`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(obj)
})
.then(res => res.json())
.then(json => {
console.log(json)
//if (json.session == false) history.push("/")
})
.catch(err => console.log(err))
},[obj])
return (
<ItemList items={contexto.productos} />
)
}
export default ItemListContainer
Here is my server:
const { Router } = require("express")
const router = Router()
const upload = require("../../utils/middlewares/multer")
let UsuariosController = require("./controller/usuariosController")
const textUsuarioYaRegistrado = "Email ya registrado!"
const textUsuarioInexistente = "Datos incorrectos!"
module.exports = (app,passport) => {
app.use("/api/usuarios", router)
let isLogin = (req, res, next) => {
try {
if (req.isAuthenticated()) {
next()
} else {
res.json({session: false})
}
} catch (error) {
console.log(error)
}
}
let isNotLogin = (req, res, next) => {
try {
if (!req.isAuthenticated()) {
next()
} else {
res.redirect(`${config.FRONT_URI}/productos`)
}
} catch (error) {
console.log(error)
}
}
//router.post("/nuevo", UsuariosController.createUsuario)
router.post("/guardar-foto", upload.single("foto"), UsuariosController.guardarFoto)
//router.post("/", UsuariosController.getUsuario)
router.post("/nuevo", passport.authenticate('register', {failureRedirect:`/api/usuarios/error/${textUsuarioYaRegistrado}`}), (req,res,next) => {
res.json(req.body)
});
router.post("/", passport.authenticate('login', {failureRedirect:`/api/usuarios/error/${textUsuarioInexistente}`}), (req,res,next) => {
res.json(req.user)
});
router.get("/error/:errorMessage", (req,res,next) => {
res.render("error", {error: req.params.errorMessage})
})
router.post("/check-session", isLogin, UsuariosController.getByEmail)

Related

How to correctly use RTK Query (SSR) with Next.js to include tokens stored in cookies

I have an application that uses Next.js, Redux, RTK Query and next-redux-wrapper and I'm having an issue with cookies not being available in a Next.js API route once store.dispatch(getMedications.initiate()) runs - the cookie is undefined on server render, but can be read fine once the page loads.
On the same page I have a useGetMedicationsQuery hook that runs, which works completely fine and can access the cookies when the query is run, however whenever the store.dispatch(getMedications.initiate()) query is run server side i.e. in the getServerSideProps the token cookie is undefined.
/pages/api/medications/get-medications.js
import axios from 'axios';
export default async (req, res) => {
const SERVICE_HOST = process.env.SERVICE_HOST;
const cookies = req.cookies;
const token = cookies.token; // undefined when initiated via store.dispatch(getMedications.initiate())
try {
const response = await axios.get(`${SERVICE_HOST}/patient/medications`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
res.status(200).json(response.data.data);
} catch(error) {
res.status(500).json(error.response);
}
}
/services/medications.js
import { createApi, fetchBaseQuery } from "#reduxjs/toolkit/dist/query/react";
import { HYDRATE } from "next-redux-wrapper";
export const medicationApi = createApi({
reducerPath: "medicationApi",
baseQuery: fetchBaseQuery({
baseUrl: 'http://localhost:3001/api/medications/',
}),
keepUnusedDataFor: 3600,
extractRehydrationInfo(action, { reducerPath }) {
if (action.type === HYDRATE) {
return action.payload[medicationApi];
}
},
tagTypes: ['Medications'],
endpoints: (build) => ({
getMedications: build.query({
query: () => `get-medications/`,
providesTags: () => ['Medications']
}),
}),
})
export const {
useGetMedicationsQuery,
util: { getRunningOperationPromises }
} = medicationApi;
export const { getMedications } = medicationApi.endpoints;
/pages/medications.js
export const getServerSideProps = wrapper.getServerSideProps(
(store) => async ({ req, res }) => {
const WEBSITE_URL = process.env.WEBSITE_URL;
const SERVICE_HOST = process.env.SERVICE_HOST;
const COOKIE_DOMAIN = process.env.COOKIE_DOMAIN || '';
const cookies = cookie.parse(req.headers.cookie || '');
const token = cookies.token;
if (!token) {
return {
redirect: {
destination: `${WEBSITE_URL}/login/${queryString(req.url)}`,
permanent: false,
}
}
}
try {
... some stuff
store.dispatch(getMedications.initiate());
await Promise.all(getRunningOperationPromises());
return {
props: {
}
}
} catch(error) {
createTokenCookie(res, COOKIE_DOMAIN, '')
return {
redirect: {
destination: `${WEBSITE_URL}/login/`,
permanent: false,
}
}
}
}
);
extractRehydrationInfo(action, { reducerPath }) {
if (action.type === HYDRATE) {
return action.payload[medicationApi];
}
},
this should be changed to
extractRehydrationInfo(action, { reducerPath }) {
if (action.type === HYDRATE) {
return action.payload[reducerPath];
}
},

Axios making 2 requests on refresh

When I navigate using Link (react router-dom) I don't have this problem, but if I refresh the browser I get a 403 error in console saying unauthorised and then I get the data in the next request with a 200 response. Why is this making what looks like 2 requests when refreshing the browser?
import { AuthContext } from "../../shared/context/auth-context";
const ContactEntries = () => {
const auth = useContext(AuthContext);
useEffect(() => {
const source = Axios.CancelToken.source();
setIsLoading(true);
const getContactEnquiries = async () => {
try {
const response = await Axios.get(
`${process.env.REACT_APP_BACKEND_URL}/v1/contact`,
{
cancelToken: source.token,
headers: { Authorization: "Bearer " + auth.token },
}
);
if (response.status === 200) {
setIsLoading(false);
setEnquiries(response.data.enquiries);
}
} catch (err) {
setIsLoading(false);
console.log(err.response);
}
};
getContactEnquiries();
return () => {
source.cancel();
};
}, [!!auth.token]);
}
Here is my authContext:
import { createContext } from "react";
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
token: null,
email: null,
firstName: null,
login: () => {},
logout: () => {},
});
This is because your useEffect is running twice on refresh. On first render it is not getting auth.token and may be it null. And on second render it is making call with 200 status code.
You have to check auth token it coming successfully.
You can check it this way
useEffect(() => {
const source = Axios.CancelToken.source();
setIsLoading(true);
const getContactEnquiries = async () => {
try {
const response = await Axios.get(
`${process.env.REACT_APP_BACKEND_URL}/v1/contact`,
{
cancelToken: source.token,
headers: { Authorization: "Bearer " + auth.token },
}
);
if (response.status === 200) {
setIsLoading(false);
setEnquiries(response.data.enquiries);
}
} catch (err) {
setIsLoading(false);
console.log(err.response);
}
};
if(auth.token) getContactEnquiries();
return () => {
source.cancel();
};
}, [!!auth.token]);

Gets 401 error while user tries to do Fetch Get request after authentication

I'm trying to get user details after user looged in but user is getting 401 error even user is looged in with 200 ok.
Explanation of process:
i have logged in user using fetch post request.
stored username,role,staffid to async storage
now i want to list all user (with /api/staff endpoint response throws user firstname and last name )with fetch get request but whenever i make GET request it
throws 401 error.
It will be lifesaver to crack this step for me,thank you!
here is my code
import AsyncStorage from "#react-native-community/async-storage";
import React, { useState, useEffect } from "react";
import { SafeAreaView, Text, StyleSheet, Alert } from "react-native";
import AuthService from "../api/auth-service";
import BASE_URL from "../api/baseUrl";
export default function HomeScreen(props) {
const [firstName, setFirstName] = useState({});
const [lastName, setLastName] = useState({});
const [userValue, setUserValue] = useState({});
useEffect(() => {
let mounted = true;
if (mounted) {
getDataFromStorage();
getUserInfo();
}
return () => {
mounted = false;
};
}, []);
const getDataFromStorage = async () => {
let user = await AsyncStorage.getItem("LoggedInUser");
setUserValue(JSON.parse(user));
};
const getUserInfo=async()=>{
return fetch(BASE_URL+"/api/staff")
.then((response) => {
if(response.ok){
console.log(response);
}else{
console.log(response.status);
}
})
.catch((error) => {
console.log(error);
this.setState({ errorMsg: "Error retreiving data" });
});
}
return (
<SafeAreaView>
<Text>
{"Good morning " + userValue.username + " "}
{"you role is " + userValue.role +"your staff id is " + userValue.staffId+" " + "your first name is "+ firstName +"this is your last name"+lastName}
</Text>
</SafeAreaView>
);
}
authservice.js
import AsyncStorage from "#react-native-community/async-storage";
import BASE_URL from "./baseUrl";
class AuthService {
login(Username, Password, role) {
console.log(Username, role);
return fetch(BASE_URL + "/api/authentication/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
Username,
Password,
}),
}).then((res) => {
if (res.ok) {
console.log("the login response", res);
return res.json();
} else {
alert("Invalid Username or Password");
window.stop();
}
});
}
logout() {
AsyncStorage.getAllKeys().then((keys) => AsyncStorage.multiRemove(keys));
}
}
export default new AuthService();
login.js
const submitData = async () => {
AuthService.login(Username, Password).then(
(data) => {
console.log(JSON.stringify(data));
AsyncStorage.setItem("LoggedInUser", JSON.stringify(data));
if (data.role == "Admin") {
console.log(data.username);
navigation.navigate("adminPage");
} else {
navigation.navigate("staffpage");
}
},
(error) => {
Alert.alert(error);
}
);
};
According to developer.mozilla.org
The HTTP 401 Unauthorized client error status response code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.
It's seems the user doesn't have right to access the API. Make sure that the getUserInfo() API, /api/staff, don't need any authentication token in header of your HTTP request.
I have a feeling that you may need to resolve one more promise in AuthService.login.
res.json() is actually a promise which needs to be resolved as well, so you may need one more then block like so:
return fetch(BASE_URL + "/api/authentication/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
Username,
Password,
}),
}).then((res) => {
if (res.ok) {
console.log("the login response", res);
return res.json();
} else {
alert("Invalid Username or Password");
window.stop();
}
}).then(finalData=>finalData )// <---------- add this
.catch(err=> err)
It happens because getDataFromStorage is an async function so you have to resolve it first. Also in login.js we have to await before navigate to make sure that the data is saved in AsyncStorage. Please update the following part of your code:
login.js
const submitData = async () => {
AuthService.login(Username, Password).then(
async (data) => {
console.log(JSON.stringify(data));
await AsyncStorage.setItem("LoggedInUser", JSON.stringify(data));
if (data.role == "Admin") {
console.log(data.username);
navigation.navigate("adminPage");
} else {
navigation.navigate("staffpage");
}
},
(error) => {
Alert.alert(error);
}
);
};
next, initialize userValue with null
const [userValue, setUserValue] = useState(null);
Now have 2 useEffect,
useEffect(() => {
let mounted = true; //Why this required as it doesn't mean anything
if (!userValue) {
getDataFromStorage();
}
return () => {
mounted = false;
};
}, []);
useEffect(()=>{
if(userValue){
getUserInfo()
}
},[userValue])

Set local storage in react

I am trying to set localstorage in react, but get undefined in value.
Even if I am using JSON.stringify, it doesn't work.
I think, the value is not reaching there.
My code looks like this:
import fetch from "isomorphic-fetch";
import { API } from "../config";
import cookie from "js-cookie";
export const signup = (user) => {
return fetch(`${API}/signup`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(user),
})
.then((response) => {
return response.json();
})
.catch((err) => console.log(err));
};
// login
export const login = (user) => {
return fetch(`${API}/login`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(user),
})
.then((response) => {
console.log(user)
return response.json();
})
.catch((err) => console.log(err));
};
// logout
export const logout = (next) => {
removeCookie("token");
removeLocalStorage("user");
next();
return fetch(`$${API}/logout`, {
method: "GET",
})
.then((response) => {
console.log("Logged Out");
})
.catch((err) => console.log(err));
};
// set cookie
export const setCookie = (key, value) => {
if (process.browser) {
cookie.set(key, value, {
expires: 1,
});
}
};
// remove cookie
export const removeCookie = (key) => {
if (process.browser) {
cookie.remove(key, {
expires: 1,
});
}
};
// get cookie
export const getCookie = (key) => {
if (process.browser) {
return cookie.get(key);
}
};
// set localstorage
export const setLocalStorage = (key, value) => {
if (process.browser) {
localStorage.setItem(key, JSON.stringify(value));
}
};
// remove localstorage
export const removeLocalStorage = (key) => {
if (process.browser) {
localStorage.removeItem(key);
}
};
// authenticate user by passing data to cookie and localstorage
export const authenticate = (data, next) => {
setCookie("token", data.token);
setLocalStorage("user", data.user);
next();
};
export const isAuth = () => {
if (process.browser) {
const cookieChecked = getCookie("token");
if (cookieChecked) {
if (localStorage.getItem("user")) {
return JSON.parse(localStorage.getItem("user"));
} else {
return false;
}
}
}
};

API login React Not Connecting

enter image description hereI'm trying to login/register a new user, however, it won't let me and I have no idea how to get it fixed. What should I do about this? I tried to find out on how to do this but it is kind of getting complicated for me and I have no idea. It's like the code doesn't want to work.
enter code here
import React, { useEffect, useState } from "react";
import LoginForm from "../LoginForm";
import Auth from "../../utils/Auth";
import { useLocation, useHistory } from "react-router";
//Uses the Auth methods to actually login with the LoginForm Component.
function Login() {
let location = useLocation();
let history = useHistory();
const [redirectToReferrer, setRedirectToReferrer] = useState(false);
useEffect(() => {
const { from } = location.state || { from: { pathname: "/protected" } };
if (redirectToReferrer) {
history.push(from);
}
}, [redirectToReferrer, history, location.state]);
/* We need to POST to the API the users info,
This will get passed down as a prop to the LoginForm */
const login = (data) => {
console.log("Logging in " + JSON.stringify(data));
//fetch('api/users/login', { is the error
fetch("api/users/login", {
method: "POST",
body: JSON.stringify(data),
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status === 200) {
//All good
Auth.authenticate(() => {
//Update the boolean and take off the cuffs
setRedirectToReferrer(true);
console.log(`Response in login ${JSON.stringify(response)}`);
});
}
})
.catch((err) => {
// No beuno, kick them
console.log("Error logging in.", err);
});
};
return (
<div>
<LoginForm onLogin={login} />
</div>
);
}
export default Login;

Resources