credentials:true
there also.I am console logging my sessionID in the middleware (before its been set) and then I log it again in the request I am using to test my sessions. In the middleware it's unidentified as expected, and then once I log it in the request, I get a real session id as expected. Everything seems to work, but when I send the request for a second time, it send back a whole new sessionID instead of persisting.
As I looked further it said it could have something to do with the cookie not being set? But I have looks all over for configuring the setting correctly like resave
and httpOnly
, and all those seem to be okay too.
What am I doing wrong, how can I fix this? I have included my package.json for client and server here first....
PACKAGE.JSON CLIENT
{
"name": "client.react",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.21.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"react-scripts": "0.9.5"
},
"devDependencies": {},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
PACKAGE.JSON SERVER
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"connect-pg-simple": "^6.2.1",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-session": "^1.17.1",
"jsonwebtoken": "^8.5.1",
"pg": "^8.5.1",
"uuid": "^8.3.2"
}
}
CLIENT
/**
* File: /src/pages/roster.js
* Date: 01-28-2021
* Author: jreyes
*
* Date | Author | Change
* ---------------------------------------------------------------------------------------
* 01-29-2021 | jreyes | initialization
* ---------------------------------------------------------------------------------------
*/
import React from 'react';
import Axios from 'axios';
const Roster = () => {
const [roster, setRoster] = React.useState([]);
/** Fetch the roster. */
const handleRoster = () => {
Axios.get("http://localhost:8080/", {
headers: {
"Content-Type":"application/json"
}
}, { withCredentials: true })
.then((response) => {
console.log(response.data);
})
}
return (
<React.Fragment>
<h1>Roster</h1>
<button onClick={handleRoster}>Get Roster</button>
</React.Fragment>
)
}
export default Roster;
CLIENT CONSOLE LOG FROM CHROME
Notice the two different sessionIDs sent back from the server. From the same roster page and I just click the button once, and then a second time.
{hit: "!/", session: "SessionID: db9af88c-0101-4bf5-82c7-f57fbe9dac1d"}
hit: "!/"
session: "SessionID: db9af88c-0101-4bf5-82c7-f57fbe9dac1d"
__proto__: Object
roster.js:25
{hit: "!/", session: "SessionID: b1a5ffd2-c986-4932-827c-a6ce644a0b3e"}
hit: "!/"
session: "SessionID: b1a5ffd2-c986-4932-827c-a6ce644a0b3e"
__proto__: Object
SERVER
/**
* File: index.js
* Date: 01-20-2021
* Author: Bennm23
*
* Date | Author | Change
* ---------------------------------------------------------------------------------------
* 01-20-2021 | benm23 | initialization
* ---------------------------------------------------------------------------------------
* 01-29-2021 | jreyes | formatted code; fixed cors; added env
* | | functionality; db is outsourced in db.js;
* ---------------------------------------------------------------------------------------
* 01-30-2021 | jreyes | added express sessions; uuid for unique strings;
* | | added request to fetch user profile.
* ---------------------------------------------------------------------------------------
*/
require('dotenv').config();
const express = require("express");
const app = express();
const db = require('./db');
const bcrypt = require("bcryptjs");
const cors = require("cors");
const {v4: uuidv4} = require('uuid');
const session = require('express-session');
const pgSession = require('connect-pg-simple')(session);
app.use(express.json());
app.use(express.urlencoded());
app.use(session({
genid: (req) => {
console.log("Inside middleware, not set yet: ");
console.log(req.sessionID);
return uuidv4();
},
store: new pgSession({
pool: db,
tableName: "session"
}),
secret: process.env.ES_SECRET,
cookie:{
maxAge:36000,
httpOnly: false,
secure: false
},
resave: false,
saveUninitialized: true
}));
app.use(cors({
origin: "http://localhost:3000",
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
}));
/** Set proper headers */
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
next();
});
/**
* Test request for sessions.
*/
app.get("/", (req, res) => {
console.log('Hit detected: defualt home route');
console.log('Session detected: ' + req.sessionID);
res.json({
"hit":"!/",
"session": "SessionID: " + req.sessionID
});
});
/**
* Register a new user.
*
* Errors:
* !email: email has been taken
* !register: database malfunction
* !hashing: hashing malfunction
*
* */
app.post("/signup", async (req, res) => {
const userExistsReq = "SELECT * FROM users WHERE email = $1";
const userExistsRes = await db.query(userExistsReq,[req.body.email]);
// Email already exists in the database.
if(userExistsRes.rowCount > 0){
res.status(200);
res.json({"error":"!email"});
}
else{
try {
// Hash password.
const salt = await bcrypt.genSalt();
const hashedPassword = await bcrypt.hash(req.body.password, salt)
const registerTemplate = "INSERT INTO users (email, password, firstname, lastname) VALUES ($1,$2,$3,$4)";
// Add user to database.
try {
const registerRes = await db.query(registerTemplate,
[
req.body.email,
hashedPassword,
req.body.firstname,
req.body.lastname
]
);
res.status(201);
res.json({"good":"register"});
// Error adding user.
} catch (err) {
res.status(500);
console.error("error: " + err);
res.json({"error":"!register"});
}
}
// Error hashing password.
catch {
res.status(500);
console.error("error: " + err)
res.json({"error":"!hashing"});
}
}
});
/**
* Login an existing user.
*
* Errors:
*
* !email: user does not exist
* !password: user entered wrong password
* !login: database malfunction.
*/
app.post("/login", async (req, res) => {
// Verify user presence in db.
const userExistsReq = "SELECT * FROM users WHERE email = $1";
const userExistsRes = await db.query(userExistsReq, [req.body.email]);
// User does not exits.
if(userExistsRes.rowCount == 0){
res.status(200);
res.json({"error":"!email"});
}
else{
// Test user credentials.
try {
if(await bcrypt.compare(req.body.password, userExistsRes.rows[0].password)){
const email = userExistsRes.rows[0].email;
const firstname = userExistsRes.rows[0].firstname;
res.status(200);
res.json({"good":"login"})
}else{
res.status(200);
res.json({"error":"!password"})
}
// Error finding user.
} catch (err) {
res.status(200);
console.error("Error while running: " + err);
res.json({"error":"!login"});
}
}
});
/**
* Fetch the roster of players.
*
* !roster: database malfunction
*/
app.get("/roster", async (req, res) => {
const fetchRosterTemplate = "SELECT * FROM users";
const response = await db.query(fetchRosterTemplate);
if (response.rowCount == 0) {
res.status(200);
res.json({"error":"!roster"});
} else {
res.status(200);
res.json(response.rows);
}
});
/**
* Start server.
*/
app.set("port", 8080);
app.listen(app.get("port"), () => {
console.log(`Find the server at http://localhost:${ app.get("port") }`);
});
SERVER CONSOLE LOG
This is the console after two requests from the roster page in my client. I click the button twice and these are the two things that are logged.
jreyes@x1carbon:~/Projects/mothers-rfc/server$ node index.js
body-parser deprecated undefined extended: provide extended option index.js:29:17
Find the server at http://localhost:8080
Inside middleware, not set yet:
undefined
Hit detected: default home route
Session detected: db9af88c-0101-4bf5-82c7-f57fbe9dac1d
Inside middleware, not set yet:
undefined
Hit detected: default home route
Session detected: b1a5ffd2-c986-4932-827c-a6ce644a0b3e
Setting httpOnly solved my issue. I had it set to false and it needs to be true. I left the secure option for cookies set to false.
httpOnly: true
solved my problem :)