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.
Related
II have an exppress app witch works correctly in dev.
However, when i do try to set cookies in prod, cookies are visible in network tab, but do not present in the browser.
I did a research and i think i covered most common problems, still cookies are not set
You may see my express app
I do add express configuration file, which i post here as well
const app = require("express")();
require("./config/express")(app);
app.disable("x-powered-by");
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "example.com");
res.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "*");
res.setHeader("Access-Control-Allow-Credentials", true);
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
if (req.method === "OPTIONS") {
// return res.sendStatus(200);
}
next();
});
//express config.js
const express = require("express");
const path = require("path");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const jwt = require("express-jwt");
const jwks = require("jwks-rsa");
const cookieSecret =
process.env.COOKIESECRET ||
"aabbcc";
// const { errorHandler } = require('../utils')
const expressSession = require("express-session");
const config = require("../config/config");
const helmet = require("helmet");
const morgan = require("morgan");
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true, limit: "50mb" }));
app.use(cookieParser()); // TRY to use it with secret as in the __express.js file
app.use(express.static("uploads"));
app.use(express.static(path.join(__dirname, "static")));
app.use(express.static(path.resolve(__basedir, "static")));
app.use("/static/uploads", express.static("static/uploads"));
app.use("/files", express.static("files"));
app.use(helmet());
app.use(morgan("combined"));
// app.use(errorHandler(err, req, res, next));
app.use(
expressSession({
secret:
"aabbcc",
resave: false,
saveUninitialized: true, cookies,
cookie: { secure: true, sameSite: "none", domain: 'example.com' },
})
);
app.set("trust proxy", 1);
};
const expiryDate = new Date(Date.now() + 60 * 60 * 1000);
res.cookie(authCookieName, token, {
expires: expiryDate,
httpOnly: true,
secure: true,
domain: "example.com",
});
res.cookie(secondCookieName, secondToken, {
expires: expiryDate,
httpOnly: true,
secure: true,
domain: "example.com",
});
res.status(200).send(user).end();
return;
After some research, it appeared, that this is the problem here
This Set-Cookie was blocked because its Domain attribute is invalid with regards to the current host URL
This is seen as message in the response-headers.
But i do set all domains correcty. I tried with https as well as without it
Does any ever had the same problems?
PS : Both Front end and back end run on subdomains of a main domain
backend.maindomain.com - my backend
frontend.maindomain.com - my frontend
maindomain.com - landing page from witch you are rediirected to the app front end if you want to use it
Solved!
It appears you need to set the main domain name as domain and cookies are being set on each subdomain
I know there are a lot of discussion about this topic already did. and i think i have followed all the instruction but still can't succeed.I think i'm missing something.
Here's my cookie :
const cookieOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES_IN * 24 * 60 * 60 * 1000
),
httpOnly: true,
path: '/',
sameSite: 'lax',
maxAge: 1000 * 60 * 60 * 1,
};
if (process.env.NODE_ENV === 'production') {
cookieOptions.secure = true;
}
res.cookie('jwt', token, cookieOptions);
Cors :
app.use(
cors({
origin: ['http://localhost:3000'],
credentials: true,
})
);
Frontend :
const { data } = await axios.post(
"http://127.0.0.1:8000/api/v1/users/login",
{
email: enteredEmail,
password: enteredPassword,
},
{ withCredentials: true }
);
I have also used axios.defaults.withCredentials = true; . But still i can't find my jwt in Application > cookies.
Here's my Response header
and this is my request header
"res.cookie()" only set the HTTP Set-Cookie header with the options provided. Any option not specified defaults to the value stated in RFC 6265.If you take a look closely at the response header, see that jwt=... is present in the Set-Cookie header.
For your implementation, where you try to access the data from the axios response, you should look into res.json() or res.send(), as it directly sends the response back in the body, not the header.
I recently built a simple real-time chat application with Nextjs on the frontend and Express on the backend. The frontend is deployed on vercel while the backend is deployed on heroku. When a user logs into the app, the backend generates a jwt token which is then sent via an HttpOnly cookie back to the frontend. Here is the code for said response:
const authenticate = async (req, res, next) => {
userService
.authenticate(req)
.then((user) => {
const { token, ...userInfo } = user;
res
.setHeader(
"Set-Cookie",
cookie.serialize("token", token, {
httpOnly: true,
secure: process.env.NODE_ENV !== "development",
maxAge: 60 * 60 * 24,
sameSite: "none",
path: "/",
})
)
.status(200)
.json(userInfo);
})
.catch(next);
};
After authentication, each subsequent request to the backend is supposed to send the token to ensure the user is logged in. For example, this is the request sent to the server to get a chat between the logged in user and another user.
const getChat = async (id) => {
const identification = id;
const response = await axios.get(
`<SERVER_URL>/chats/chat/${identification}`,
{ withCredentials: true }
);
return response;
};
In development when on localhost:3000 for the frontend and localhost:4000 for the backend, everything works fine. However, when I deployed the frontend to vercel and the backend to heroku, the browser simply refuses to save the cookie! The jwt token appears in the response header after sending the authentication request, but it isn't saved to the browser. I have tried absolutely everything I can think of, including changing the cookie parameters, but I can't get it to work. I am pretty sure I have cors properly configured on the backend as well, along with the cookie-parser module:
const cors = require("cors");
const cookieParser = require("cookie-parser");
app.use(
cors({
origin: "<CLIENT_URL>",
credentials: true,
})
app.use(cookieParser());
Thanks for taking the time to read this, any help would be greatly appreciated! And my apologies if I have not elaborated enough, this is my first post here and I'm still trying to learn the proper etiquette of the site!
HttpOnly can not read or write on client-side but when the first HttpOnly send through a request other request on the same origin can access the coockies in backend but you should request in Next.js like this.
Next.js using fetch :
const req = await fetch("http://localhost:7000/api/auth/login", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Credentials": true,
},
body: JSON.stringify({
email: formData.get("email"),
password: formData.get("password"),
}),
});
const data = await req.json();
then in backend you can read the coockie through coockie-parser
server.js:
const cookieParser = require("cookie-parser");
app.use(coockieParser());
route.post('/login',(req,res) => {
if(user){
res
.cookie("access_token", newToken, {
httpOnly: true,
secure: process.env.NODE_ENV === "production" ? true : false,
})
.status(200)
.json({ ok: true, payload: data });
}
})
Now you can read this cookie in other routes but sure about the expiration time.
I am currently making a Next.js app and I am having issues with cookies. I have an express API running on localhost:3001 which sets cookies when I signup/signin using express-cookie-session library. Whenever I do it through postman it works fine, however when I do it from next app an api it doesn't have "Set-Cookie" header in the response. I suspect it has to do with next app and express being on different ports and express being unable to set cookies to the next app however I'm unsure what to do about it. If it matters I wanted to set JWT's this way. It's possible to send them in response body but I would like to know how I could do it through the cookies.
Here are some relevant configurations:
app.use(cors());
app.set('trust proxy', true);
...
app.use(cookieSession({ signed: false, secure: false, sameSite: "lax" }));
a sign up controller:
const signUp = async (req: Request, res: Response, next: NextFunction) => {
...
const accessToken = TokenGenerator.generateAccessToken(user);
const refreshToken = TokenGenerator.generateRefreshToken(user);
user.refreshToken = refreshToken;
...
req.session = { accessToken, refreshToken };
res.send(user);
};
and getServerSideProps function
export const getServerSideProps = async (ctx) => {
const headers = ctx.req.headers;
const res = await axios.get("http://localhost:3001/users/current-user", {
headers,
});
return { props: { data: res.data } };
};
EDIT: Set-Cookie header is actually shown in chrome console however it isn't being console logged from axios response.
Here's example of cookie:
Set-Cookie: express:sess=eyJhY2Nlc3NUb2tlbiI6ImV5SmhiR2NpT2lKSVV6STFOaUlz
SW5SNWNDSTZJa3BYVkNKOS5leUpwWkNJNklqVm1abVEyTldSalpURXlaak5pT0RVellUWXlNR0
psT0NJc0ltVnRZV2xzSWpvaWJHdHNiaUlzSW1saGRDSTZNVFl4TURRME1qSXdOQ3dpWlhod0lq
b3hOakV3TkRReU1qRTVmUS5NN2szX1BVQy1hbzRQb2w4OXNiS05ndS1ndkpqNEVfUWdoX2RHSU
ZrZlZFIiwicmVmcmVzaFRva2VuIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhW
Q0o5LmV5SnBaQ0k2SWpWbVptUTJOV1JqWlRFeVpqTmlPRFV6WVRZeU1HSmxPQ0lzSW1WdFlXbH
NJam9pYkd0c2JpSXNJbWxoZENJNk1UWXhNRFEwTWpJd05IMC5JdHA2WHh4aFRPMWJUc0oydGNM
ZU9hdFB3cWZWdWRsVmRQWkNnejB3eS1rIn0=; path=/; domain=http://localhost:3000.
I found a solution to this by adding this line to my server configuration:
app.use(cors({ origin: "http://localhost:3000", credentials: true }));
as well as setting withCredentials to true on my axios request.
It's strange, but I don't see some set-cookie headers from my express server in react-native app only on android devices!
I use express on my node.js server
const express = require('express');
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const bodyParser = require('body-parser');
app.use(cookieParser());
app.use(session({
name: 'sid',
secret: CONSTANTS.SESSION_SECRET,
resave: false,
saveUninitialized: true
}));
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
const csrfProtection = csrf();
app.use(csrfProtection);
app.get('/', (request, response, next) => {
response.cookie('csrftoken', request.csrfToken());
response.status(200).send(...);
});
I just set csrftoken cookie and send some response;
On client i just get mail page as first:
fetch(URL_INDEX, {
method: 'GET',
headers: {
'User-Agent': USER_AGENT,
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
}
}).then((response) => {
//check response here <--------------------------------
processCookies(response);
return response;
})
What I see in debugger in fetch answer:
In IOS
Headers
map:Object
connection:"keep-alive"
content-length:"11716"
content-type:"text/html; charset=utf-8"
date:"Fri, 08 Feb 2019 10:58:25 GMT"
etag:"W/"2dc4-Ew7HRSMcOHECQlBtXIfAuuPw/Vs""
set-cookie:"csrftoken=bzKoDm5w-CdiLpGk0NWZ1TxaACRNJoRvVeng; Path=/, sid=s%3AGLvycaobuCL7xyIiNRBCXHSZU3SmHmAJ.vv9dzPurvicFvMb%2FkeB9Lshy6ZAQ0SvsMm8cR2ij9O8; Path=/; HttpOnly"
x-powered-by:"Express"
In Android
Headers
map: Object
connection:"keep-alive"
content-length:"11716"
content-type:"text/html; charset=utf-8"
date:"Fri, 08 Feb 2019 10:52:52 GMT"
etag:"W/"2dc4-Ew7HRSMcOHECQlBtXIfAuuPw/Vs""
set-cookie:"sid=s%3AOgeCB1Xsu8yA0SKiXF5Xgdc5pE-gSjfs.cDNHgzc41X1JmnUKmY6Hn3J2%2BrjxbXpBt7%2FhXwN6HbQ; Path=/; HttpOnly"
x-powered-by:"Express"
As you can see csrftoken cookie exists in response on ios, but we don't see it on android.
Any ideas?