In dev mode (express on localhost:4000, vue on localhost:8080) works fine, all cookies saving correct. In production mode i change cors settings and axios.defaults.baseURL, and... client dont save cookies...
but response request contains set-cookie header
backend cors settings:
app.use(
cors({
credentials: true,
origin: process.env.CLIENT_URL
})
)
backend session settings:
app.use(
session({
store: new redisStore({
host: 'localhost', port: 6379, client: redisClient, ttl: 86400
}),
name: '_TS',
secret: process.env.SESSION_SECRET,
resave: false,
cookie: { secure: false, maxAge: 600000 },
saveUninitialized: true
})
);
frontend:
axios.defaults.withCredentials = true
axios.defaults.baseURL = 'http://my-domain.com';
(contain session cookie!)
(session cookie is missing)
P.S. Postman works correctly, and saving cookies fine.
Related
Client
axios.defaults.headers.common['Content-type'] = "application/json"
axios.defaults.baseURL = 'http://localhost:5000'
axios.defaults.withCredentials = true;
const resp = await axios.post('/auth/login',{user:user},{
withCredentials: true })
Server
app.use(cors({
origin:['http://<clienturl>'],
credentials: true,
}))
response...
const cookieOptions={
secure: process.env.NODE_ENV !== "development",
httpOnly: true,
sameSite: 'none',
path:'/'
}
res.cookie("auth", tokenstring , cookieOptions)
.send(ApiResponse.success("Voila!"))
in the Network tab I see
login (preflight)
login (xhr) : I can see in response headers Set-Cookie: auth=token
but no cookie in Cookies being set no matter if it's httpOnly or not...
Pay attention: Client-Server different origin.
I'm trying to use JWT authentication for my app and save the token as an httpOnly cookie to use for subsequent requests. The requests work in Insomnia, setting and then using the cookie to login, but don't work in my NextJS frontend.
My frontend is at localhost:3000 and my backend is at localhost:3001 but I have cors set.
app.use(
cors({
origin: "http://localhost:3000",
optionsSuccessStatus: 200,
credentials: true,
})
);
app.use(cookieParser());
My request for data once logged in looks like this:
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
body: JSON.stringify(data),
};
fetch(url, options)
.then((res) => res.json())
.then((res) => {
// Do stuff
});
On the server I set the token using
res.cookie("token", token, {
httpOnly: true,
secure: true,
});
but when I console log req.cookies.token on the server for the data request I get undefined. Is there something I'm doing wrong that's preventing the cookie from getting set/sent?
Or is this related to localhost not setting cookies? I thought that didn't apply for httpOnly cookies. Thanks!
You're setting the secure parameter on your cookie. This means that the browser will drop the cookie if the connection to your backend is not over SSL.
You would have to configure your backend to use SSL (probably with some self-signed certificates) or set the secure parameter on your cookie to false.
I'm getting a cookie locally but not once I deploy to Heroku using the heroku-redis plugin. I know that Heroku is working alright because my herokup-posgres URL is working. I have been trying to figure this out for a couple days and I'm not sure what to do.
Apollo client:
const client = new ApolloClient({
uri:
process.env.NODE_ENV === "production"
? "https://podapi.herokuapp.com/graphql"
: "http://localhost:4000/graphql",
cache: new InMemoryCache(),
credentials: "include",
});
Cors:
const corsOptions = {
origin: process.env.NODE_ENV === "production"
? (process.env.VERCEL_APP as string)
: (process.env.LOCALHOST_FRONTEND as string),
credentials: true,
};
Add redis to express
const app = express();
app.set("trust proxy", 1);
const RedisStore = connectRedis(session);
const redis = new Redis();
app.use(cors(corsOptions));
app.use(
session({
name: "qid",
store: new RedisStore({
client: redis,
disableTTL: true,
url: process.env.NODE_ENV === "production" ? process.env.REDIS_URL : undefined,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
httpOnly: true,
sameSite: "lax",
secure: process.env.NODE_ENV === "production" ,
domain: process.env.NODE_ENV === "production" ? "podapi.herokuapp.com" : "localhost",
},
saveUninitialized: false,
secret: "mySecret",
resave: false,
})
);
Things I've tried: Adding the domain in the cookie (it doesn't work with or without it); Hard coding process.env.NODE_ENV to "production" incase it wasn't actually running production; I've added many little things like credentials: true/"include"; I've since added app.set("trust proxy", 1);
Any ideas or advice would be incredibly helpful.
So I have this weird thing going on where the axios requests I make from the front end do not get the response I'm sending from the server, but it only happens when I set the store in express session.
I am making a post request to the login route like in this function
const logIn = async (formData) => {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const response = await axios.post("/login", formData, config);
// do something with the response
};
When I make the request the server responds with status 200 and a user object. When I check the network tab in the browser devtools, I see that it is getting the correct response and the payload is showing the right user object as well
However axios never returns and is left hanging forever.
Now here's the kicker. This only happens if I set the store on the express session in my app.js
import express from "express";
import router from "./routes/router.js";
import session from "express-session";
import "dotenv/config";
import redis from "redis";
import connectRedis from "connect-redis";
const PORT = process.env.PORT || 5000;
const app = express();
const redisClient = redis.createClient();
redisClient.connect();
redisClient.on("connect", () => {
console.log("redis client connected");
});
const RedisStore = connectRedis(session);
app.use(
session({
name: "qid",
store: new RedisStore({ client: redisClient }), // RIGHT HERE
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365,
httpOnly: true,
sameSite: "lax",
secure: false,
},
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
resave: false,
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/", router);
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
As soon as I comment out the line where I set the store, Axios gets the response and everything works perfectly. So I have to assume that the session store is somehow blocking the server response from getting to axios.
Do you have any idea why that might be?
I ran into the exact same issue, but I could finally solve this for my setup by using ioredis instead of redis.
I updated your app.js accordingly
import express from "express";
import router from "./routes/router.js";
import session from "express-session";
import "dotenv/config";
import Redis from 'ioredis';
import connectRedis from "connect-redis";
const PORT = process.env.PORT || 5000;
const app = express();
const redisClient = new Redis();
redisClient.on("connect", () => {
console.log("redis client connected");
});
const RedisStore = connectRedis(session);
app.use(
session({
name: "qid",
store: new RedisStore({ client: redisClient }), // RIGHT HERE
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365,
httpOnly: true,
sameSite: "lax",
secure: false,
},
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
resave: false,
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/", router);
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
My NEST api works on localhost but cookies are not working on heroku.
Here is my config
app.enableCors({ origin: process.env.FRONT_END_URL, credentials: true }); // FE_URL == http://localhost:3000 (a react app)
app.set('trust proxy', 1); // I've seen people using express using this, but isn't working here
app.use((req, res, next) => {
req.connection.proxySecure = true; // If i don't do this, it'll throw an error if i'm using secure == true and sameSite == 'none'
next();
});
app.use(
sessions({
cookieName: 'FEATSession',
secret: 'ThisIsMyTopSecretWord',
duration: 24 * 60 * 60 * 1000,
activeDuration: 1000 * 60 * 5,
cookie: {
path: '/', // Tried '/' and not setting this prop too
// domain: 'feat-be.herokuapp.com', // I tried using and not using it too
sameSite: 'none',
secure: true,
httpOnly: true, // Tried true and false too
},
}),
);
Everything else is working fine, only cookies doesn't.
I've just solved myself a very similar problem today, try different syntax of setting cookie:
SameSite property invalid Cookies HTTPONLY MERN