I'm storing cookies on my server, but when I tried to access them. Object Returns Null.
code I'm using to store my cookies. This is done when I'm logging in!
res.cookie("accessToken", accessToken, {
httpOnly: true,
secure: true,
expires: new Date(Date.now() + oneDay),
});
res.cookie("refreshToken", refreshToken, {
httpOnly: true,
secure: true,
expires: new Date(Date.now() + oneDay),
});
index.ts
const dotenv = require("dotenv");
dotenv.config();
const PORT = process.env.PORT || 3001;
const cookies = require("cookie-parser");
const express = require("express");
const app = express();
const cors = require("cors");
app.use(cors());
app.use(express.json());
app.use(cookies());
import dbConnect from "./db/connect";
import adminAuthRoter from "./routes/admin/adminAuthRouter";
app.get("/", (req: any, res: any) => {
res.send("Hello World");
});
app.use("/api/v1/adminauth", adminAuthRoter);
const start = async () => {
try {
await dbConnect(process.env.MONGODB_URI);
app.listen(PORT, () =>
console.log(`Server is listening on port ${PORT}...`)
);
} catch (error) {
console.log(error);
}
};
start();
When I tried to console.log(req.cookies) or console.log(req.signedCookies) my response is empty. But when I see my Postmon cookies there are cookies stored
Postmon Cookie Reponse Image
What may be the issue here?
Related
I have a semi successful deployment to heroku but the calls to the server are saying CONNECTION REFUSED and I can't figure it out.
I can hit the route and it returns correctly in postman but not in production
Below is the services file (the ones with /api in front are the ones being called)enter image description here
`import http from "../utils/http-common";
class CountriesService {
getAll() {
return http.get("/api/country");
}
getAllCountries() {
return http.get("/country/getAll");
}
getScroll(skip) {
return http.get(`/country?skip=${skip}`);
}
get(id) {
return http.get(`/country/${id}`);
}
create(countryForm) {
return http.post("/country/new", countryForm);
}
edit(id, values) {
return http.put(`/country/${id}`, values);
}
delete(id) {
return http.delete(`/country/${id}`);
}
}
export const getPostsPage = async (pageParam = 1, options = {}) => {
const response = await http.get(`/api/country?_page=${pageParam}`, options)
return response.data
}
export default new CountriesService();
`
This is the http-common
import axios from "axios";
var url;
process.env.REACT_APP_NODE_ENV === "production"
? (url = "")
: (url = "http://localhost:5000/");
export default axios.create({
baseURL: `${url}`,
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
});
this is the server file on the backend with a proxy from the frontend to localhost 5000
const path = require('path');
require("dotenv").config();
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const cors = require("cors");
var morgan = require("morgan");
const MongoDBStore = require('connect-mongo');
const mongoSanitize = require('express-mongo-sanitize');
const helmet = require('helmet');
// Models
const User = require("./models/user.js");
// Passport Config
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const flash = require("connect-flash");
const session = require("express-session");
const cookieParser = require("cookie-parser");
// const { MongoClient } = require("mongodb");
const BodyParser = require("body-parser");
const { storage } = require("./imageupload/cloudinary");
const userAuthRoute = require("./routes/user.js");
const reviewRoute = require("./routes/review.js");
const countryRoute = require("./routes/country.js");
const cityRoute = require("./routes/city.js");
const activityRoute = require("./routes/activity.js");
const restaurantRoute = require("./routes/restaurant.js");
const dishesRoute = require('./routes/dishes.js');
const outdoorsRoute = require('./routes/outdoors.js');
const apiRoutes = require("./routes/api.js");
const cityReviewRoute = require("./routes/cityReviews.js");
const foodRoute = require('./routes/food.js');
const landmarkRoute = require('./routes/landmark.js');
const searchRoute = require('./routes/search.js');
const contactRoute = require('./routes/contact.js');
const db_url = process.env.DB_URL;
const PORT = process.env.PORT || 5000;
const secret = process.env.SESSION_SECRET;
// const client = new MongoClient(process.env.DB_URL);
const corsOptions = {
origin: [
"http://localhost:3000",
"http://localhost:5000",
"https://geopilot.herokuapp.com",],
credentials: true,
optionSuccessStatus:200,
};
app.use(cors(corsOptions));
app.use(express.json());
app.use(mongoSanitize({ replaceWith: "_" }));
app.use(BodyParser.json());
app.use(express.urlencoded({ extended: true }));
app.use(morgan("tiny"));
// app.use(cookieParser());
mongoose
.connect(db_url)
.then(() => {
console.log("database connection established successfully");
})
.catch((error) => console.log("this is the error", error));
const store = MongoDBStore.create({
mongoUrl: process.env.DB_URL,
ttl: 24 * 60 * 60 * 365, // 1 year
autoRemove: 'native',
crypto: {
secret,
},
});
store.on('error', function(error) {
console.log('SESSION STORE ERROR:', error);
});
// Session Settings
const sessionOptions = {
name: "geopilot_session",
secret: secret,
store: store,
resave: false,
saveUninitialized: false,
cookie: {
samesite: false,
// httpOnly: true,
// secure: true,
expires: Date.now() + 1000 * 60 * 60 * 24 * 365,
maxAge: 1000 * 60 * 60 * 24 * 365,
},
};
// app.set('trust proxy', 1) // trust first proxy
// Session Setup
app.use(session(sessionOptions));
// Helmet Setup
// app.use(helmet())
// Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
// Routes
app.use("/api/country/:countryId/reviews", reviewRoute);
app.use("/api/country", countryRoute);
app.use('/api/city', cityRoute);
app.use('/api/city/:cityId/reviews', cityReviewRoute);
app.use('/api/activity', activityRoute);
app.use('/api/restaurant', restaurantRoute);
app.use('/api/restaurant/:restaurantId/reviews', reviewRoute);
app.use('/api/landmark', landmarkRoute);
app.use('/api/landmark/:landmarkId/reviews', reviewRoute);
app.use('/api/food', foodRoute);
app.use('/api/dishes', dishesRoute);
app.use('/api/outdoor', outdoorsRoute);
app.use('/api/search', searchRoute);
app.use('/api/user', userAuthRoute);
app.use('/api/contact', contactRoute);
// ----------- Deployment -----------
__dirname = path.resolve();
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "../client/build")));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "../client", "build", "index.html"));
});
}
// ----------- Deployment -----------
app.get("*", () => {
res.send("PAGE NOT FOUND");
});
I tried requesting in postman which works.
I tried changing things in the package.json to help proxy or run server.
I tried to switch endpoints and change CORS policy but it won't work.
For anyone seeing this and is stuck, I changed http-common baseUrl to match my website url (not localhost) and then had to do "npm run build" to make it actually implement the changes.
I'm trying to get a test React frontend and Node/Express backend to correctly set session cookies at Heroku.
This frontend/backend work locally.
This frontend/backend work at Heroku in every browser on my development machine.
But on every other machine I have tested (Windows, Ubuntu), I get this Cross-Origin-Request-Blocked error:
Here is the backend code, where I configure CORS origin correctly:
import express from 'express'
import cors from 'cors'
import morgan from 'morgan'
import session from 'express-session';
import dotenv from 'dotenv';
import cookieParser from 'cookie-parser';
dotenv.config();
const app = express();
app.use(morgan("dev"));
app.set('trust proxy', 1);
app.use(cors({
origin: process.env.FRONTEND_ORIGIN,
credentials: true
}));
app.use(cookieParser());
app.use(session({
name: 'testsession',
secret: 'h$lYS$cr§t!',
resave: true,
saveUninitialized: true,
cookie: {
httpOnly: true,
maxAge: 60 * 60 * 24,
sameSite: process.env.NODE_ENV === "production" ? "none" : "lax",
secure: process.env.NODE_ENV === "production"
}
}))
app.get('/', (req, res) => {
let user = req.session.user;
if (!user) {
res.json({ message: `${(new Date()).toISOString()}: nobody is logged in` })
} else {
res.json({ message: `${(new Date()).toISOString()}: ${user} is logged in` })
}
});
app.get('/login', (req, res) => {
req.session.user = "user001"
res.json({
message: `${(new Date()).toISOString()}: ${req.session.user} is now logged in`
})
})
app.get('/logout', (req, res) => {
req.session.destroy();
res.json({ message: `${(new Date()).toISOString()}: user logged out` })
});
const PORT = process.env.PORT || 3011
app.listen(PORT, () => {
console.log(`API listening on http://localhost:${PORT}`);
});
Here is my frontend code:
import { useState } from 'react';
import './App.scss';
function App() {
const [message, setMessage] = useState('click a button');
const backendUrl = process.env.REACT_APP_BACKEND_URL;
const handle_checkuser = async () => {
const requestOptions = {
method: 'GET',
credentials: 'include'
};
const response = await fetch(backendUrl, requestOptions);
const data = await response.json();
setMessage(data.message);
}
const handle_login = async () => {
const requestOptions = {
method: 'GET',
credentials: 'include'
};
const response = await fetch(`${backendUrl}/login`, requestOptions);
const data = await response.json();
setMessage(data.message);
}
const handle_logout = async () => {
const requestOptions = {
method: 'GET',
credentials: 'include'
};
const response = await fetch(`${backendUrl}/logout`, requestOptions);
const data = await response.json();
setMessage(data.message);
}
return (
<div className="App">
<div><button onClick={handle_checkuser}>checkuser</button></div>
<div><button onClick={handle_login}>login</button></div>
<div><button onClick={handle_logout}>logout</button></div>
<div>{message}</div>
</div>
);
}
export default App;
Why would it be getting this CORS error with some machines and not others?
Backend:
https://github.com/edwardtanguay/et-cookietest-backend
https://et-cookietest-backend.herokuapp.com
Frontend:
https://github.com/edwardtanguay/et-cookietest-frontend
https://et-cookietest-frontend.herokuapp.com
ADDENDUM
I also noticed that on every other machine except for my development machine, the HTTP connection is not secure. This seems to be the cause of the cookie-setting problem.
But how can that be? Why would one particular computer receive HTTPS connections from a website and others HTTP?
Hello Stackoverflow Community.
So I am encountering a very weird problem when hosting my nextjs powered by express with openlitespeed. Everything works great in production, except one thing - the authentification of sessions. The user is saved in the cookies correctly and it works if you are not idle for more than a minute on the page you are on, but if you are idle for more than a minute, then the request is not authenticated anymore even though the cookie is still there.
I am using redis for my cookie store, and everything works in local testing, where openlitespeed is not present. The authentification I am using is passportjs with express-session. Have any of you encountered this problem, and if so, how did you solve it?
I have tried disabling the cache module, set all timeouts to a higher value or disabling them, use different memorystores and more, but no luck. Here is the server.js file, however, I do not believe it has something to do with the code itself, but rather the config of openlitespeed:
const express = require('express')
const next = require('next')
const passport = require('passport');
const redis = require('redis')
const session = require('express-session')
const {v4: uuidv4} = require('uuid');
const path = require('path');
const log = require('./logger')
let RedisStore = require('connect-redis')(session)
let redisClient = redis.createClient()
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
//Json parsing
server.use(express.json());
server.use(express.urlencoded({extended: true}));
if (dev){
//Express session
server.use(session({
store: new RedisStore({ client: redisClient }),
genid: function() {
return uuidv4()},
secret: uuidv4(),
resave: false,
saveUninitialized: false,
cookie: {
secure: false,
maxAge: 86400000
}
}))
}
else{
//Express session
server.use(session({
store: new RedisStore({ client: redisClient }),
genid: function() {
return uuidv4()},
secret: uuidv4(),
proxy: true,
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
maxAge: 86400000
}
}))
}
//Passport auth
server.use(passport.initialize());
server.use(passport.session());
//Import of the passport config
const initializePassport = require('./passport-config');
initializePassport(passport);
//Login route
server.post('/login', passport.authenticate('login'), (req, res) => {
res.send({message: 'Successful login', login: true})
});
const passportLogout = function (req, res, next) {
req.logout()
next()
}
//Logout route
server.get('/logout', passportLogout, (req, res) => {
req.session.destroy();
res.redirect('/login');
});
//Import registrerings route. Pga. brugen af route i stedet for app kan vi bruge denne middleware med en anden underside, hvis vi f.eks. ville gøre så admins også kunne lave brugere.
const registerRoute = require('./routes/register-user');
server.use('/register', registerRoute);
//User routes hvor login er required. Rendering. Skal stå under called til initializepassport, ellers kan den ikke finde ud af at den er authenticated via passport, og auth.js returnerer dig derfor til login
const usersRoutes = require('./routes/user/user-routes');
server.use(usersRoutes);
//Admin routes til rendering
const adminRoutes = require('./routes/admin/admin-routes');
server.use(adminRoutes);
const indexRoutes = require('./routes/index-routes');
server.use(indexRoutes);
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, (err) => {
if (err) throw err
log.logger.log({
level: "info",
message: `Server was started on ${port}`,
additional: "properties",
are: "passed along",
});
console.log(`> Ready on http://localhost:${port}`)
})
})
All right, so I figured it out finally. The configuration for Openlitespeed was set, so that it could create as many httpd workers as it wants. Therefore, when a new was created and the requests went over to that one, it seems the authentification did not stick. I have fixed this by setting the "Number of Workers" to 1 under Server Configuration -> Server Process -> Number of Workers.
As for my server.js file I used to setup nextjs and openlitespeed:
const express = require("express");
const next = require("next");
const passport = require("passport");
const redis = require("redis");
const session = require("express-session");
const { v4: uuidv4 } = require("uuid");
const path = require("path");
const log = require("./logger");
let RedisStore = require("connect-redis")(session);
let redisClient = redis.createClient({ auth_pass: process.env.DB_PASSWORD });
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
//Json parsing
server.use(express.json());
server.use(express.urlencoded({ extended: true }));
if (dev) {
//Express session
server.use(
session({
store: new RedisStore({ client: redisClient }),
genid: function () {
return uuidv4();
},
secret: uuidv4(),
resave: false,
saveUninitialized: false,
cookie: {
secure: false,
maxAge: 86400000,
},
})
);
} else {
//Express session
server.use(
session({
store: new RedisStore({ client: redisClient }),
genid: function () {
return uuidv4();
},
secret: uuidv4(),
proxy: true,
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
maxAge: 86400000,
},
})
);
}
//Passport auth
server.use(passport.initialize());
server.use(passport.session());
//Import of the passport config
const initializePassport = require("./passport-config");
initializePassport(passport);
//Login route
server.post("/login", passport.authenticate("login"), (req, res) => {
res.send({ message: "Successful login", login: true });
});
const passportLogout = function (req, res, next) {
req.logout();
next();
};
//Logout route
server.get("/logout", passportLogout, (req, res) => {
req.session.destroy();
res.redirect("/login");
});
//Import registrerings route. Pga. brugen af route i stedet for app kan vi bruge denne middleware med en anden underside, hvis vi f.eks. ville gøre så admins også kunne lave brugere.
const registerRoute = require("./routes/register-user");
server.use("/register", registerRoute);
//User routes hvor login er required. Rendering. Skal stå under called til initializepassport, ellers kan den ikke finde ud af at den er authenticated via passport, og auth.js returnerer dig derfor til login
const usersRoutes = require("./routes/user/user-routes");
server.use(usersRoutes);
//Admin routes til rendering
const adminRoutes = require("./routes/admin/admin-routes");
server.use(adminRoutes);
const indexRoutes = require("./routes/index-routes");
server.use(indexRoutes);
server.all("*", (req, res) => {
return handle(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on ${port}`);
});
});
Faced such a problem and can no longer solve it 2 days, please help.
There is a server on the nodejs:
index.js
const mongoose = require("mongoose");
const keys = require("./config/keys");
const app = require("./app");
const port = process.env.PORT || 3001;
mongoose
.connect(keys.MONGO_URL, { useNewUrlParser: true })
.then(() => {
app.listen(port, () => console.log(`Server started on port ${port}`));
console.log("Connected to" + " MongoDB");
})
.catch((error) => console.log(error));
app.js
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const morgan = require("morgan");
const passport = require("passport");
const authRoutes = require("./routes/auth");
const restaurantRoutes = require("./routes/restaurant");
const app = express();
app.use(passport.initialize());
require("./middleware/passport")(passport);
app.use(morgan("dev"));
app.use("/uploads", express.static("uploads"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
app.use("/api/auth", authRoutes);
app.use("/api/restaurant", restaurantRoutes);
module.exports = app;
Nested Routes:
router.get(
"/",
passport.authenticate("jwt", { session: false }),
controller.getAll
);
router.get(
"/:id",
passport.authenticate("jwt", { session: false }),
controller.getById
);
router.post(
"/create",
passport.authenticate("jwt", { session: false }),
upload.single("image"),
controller.create
);
router.patch(
"/update",
passport.authenticate("jwt", { session: false }),
upload.single("image"),
controller.update
);
router.delete(
"/:id",
passport.authenticate("jwt", { session: false }),
controller.delete
);
There is a request from the front:
export function createNewRestaurant(restaurant, token) {
return {
type: CREATE_NEW_RESTAURANT,
payload: axios({
type: "POST",
url: "api/restaurant/create",
headers: {
Authorization: token,
},
data: JSON.stringify(restaurant),
})
.then((response) => {
console.log(response);
// return response.data;
})
.catch((error) => {
console.log({ error });
// return error.response.data;
}),
};
}
The problem is that POST doesn't even get from the server ...
There is no mention of it in the server console
If you remove the line from package.json client
"proxy": "http://localhost:3001/"
and write in the request
url: "http://localhost:3001/api/restaurant/create",
then in the server console we will see the OPTIONS request
OPTIONS /api/restaurant/create 204 0.135 ms - 0
I understand that the case is CORS, but I have it installed and in theory should work it all out, but how does this happen?
In postman, the request goes fine
when i hit the below express server from my react app which is running on port 3000 there is no cookie delivered however in postman there is?
const cookieParser = require("cookie-parser");
const express = require("express");
const cors = require("cors");
const app = express();
app.use(cors());
app.use(cookieParser());
app.get("/api", function (req, res, next) {
const cookieOptions = {
expires: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
secure: false,
httpOnly: true,
};
res.cookie("isCookie", "react cookie", cookieOptions);
res.status(200).json({
status: "success",
});
});
app.listen(7000, () => {
console.log("listening on port 7000");
});
the client side react component making the request
import React, { useEffect } from "react";
function App() {
async function getCookie() {
let res = await fetch("http://localhost:7000/api");
res = await res.json();
console.log(res);
}
useEffect(() => {
getCookie();
}, []);
return <div className="App">App</div>;
}
export default App;