Here I am trying to integrate session handling in a ReactJS application with express-server back-end. However, Inspite of all the suggestions available out their in all of the forums and communities, I am not able to receive the session cookie on the client (ReactJS).
React client is running on http://localhost:5173 and Express server is running on http://localhost:3001
Here is my 'app.ts' (express-server configuration setup)
export const MemoryStore = require("memorystore")(session);
export const sessionStore = new MemoryStore({
checkPeriod: 3600000, // prune expired entries every 24h
});
export const app = express();
app.use(morgan("dev"));
app.use(json());
app.use(
cors({
origin: ["http://localhost:5173","http://localhost:3001"],
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
credentials: true,
exposedHeaders: ["set-cookie"],
})
);
app.use((req, res, next) => {
res.header("Access-control-Allow-Origin", "http://localhost:5173");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, set-cookie"
);
res.header("Access-Control-Allow-Credentials", 'true');
if (req.method === "OPTIONS") {
res.header("Access-Control-Allow-Methods", "PUT, POST, PATCH, DELETE, GET");
return res.status(200).json({});
}
next();
});
app.use(
session({
name: "react_session",
secret: "react_session_key",
resave: false,
saveUninitialized: false,
store: sessionStore,
cookie: {
httpOnly: true,
maxAge: 3600000,
sameSite: "lax",
secure: false,
domain: 'localhost'
},
})
);
app.use(authRouter);
app.listen(3001, () => console.log(`server is running`));
I have successfully implemented Google Authentication for ReactJS app and upon receiving the ID token from Auth server, I would like to populate the session.user attribute with the email value from token.
The API endpoints in Express-server performing authentication job are implemented as follows :
authRouter.post("/api/auth/google", async (req: Request, res: Response) => {
const { tokens } = await oAuth2Client.getToken(atob(req.body.code)); // exchange code for tokens
// Explicitly set cookie is correctly received by the client.
/*res.cookie("react_token", JSON.stringify(req.session.id), {
maxAge: 1000 * 60 * 60,
httpOnly: false,
secure: false,
domain: "localhost",
});*/
console.log(
`session id user session [id = ${req.session.id} ] ` +
JSON.stringify(req.cookies)
);
// Following line prints new session id for each request. This means the session is created on the server
// But no set-cookie response header is sent back to the client.
sessionStore.all((error: Error, sessions: any) => {});
res.json(tokens);
});
authRouter.get(
"/api/auth/checksession",
async (req: Request, res: Response) => {
console.log(
`session id user session [id = ${req.session.id} ] ` +
JSON.stringify(req.cookies)
);
sessionStore.all((error: Error, sessions: any) => {});
res.send({ sessionId: req.session.id });
}
);
From React JS client application, after receiving a successful token response from "/api/auth/google", I am immediately issuing 2 http requests to a dummy 'checksession' endpoint one after another to prove the existence of a persistent session across requests. Unfortunately, for each request to '/checksession' endpoint, a new 'sessionId' value is printed.
In my React Client app,
fetch("http://localhost:3001/api/auth/checksession", {
method: "GET",
credentials : "include",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
}).then((response) => {
// UNABLE TO RECIEVE ANY SESSION COOKIE HERE
// HOWEVER any custom cookie sent by server is received here.
console.log('document cookies USER AUTH === ' + document.cookie)
console.log('response headers for USER AUTH === ' + response.headers.getSetCookie());
});
Honesly, I have tried all combinations of 'secure:true/false', 'samesite:none/lax', but nothing seem to be working.
Any help will be much appreciated.