Response header Set-Cookie doesn't store cookies in browser - browser

I'm setting 2 cookies in response from backend to the browser.
One that is secure HTTPOnly (it's refreshToken) and the other one without those parameters so it's accessible to JavaScript (carrying information about refreshToken is set and when it expires).
Cookies in response:
Neither of those two is set in browser. I studied all about cookies and I'll be honest, I'm lost here and need your help.
At first it was working very well on my localhost environment (backend on localhost:8080, frontend on localhost:3000).
Then I made deploy and there it was NOT working.
I tested again on localhost and I checked "Disable cache" to prevent unwanted behaviour and it is not working even there.
I'll mention that I'm using CORS, not sure if that can may interfere:
I tested this both in Chrome and Firefox.

I FINALY figured it out. Cookies are valid. The answer is to set withCredentials = true both in frontend and backend.
First I thought the parameter withCredentials on frontend is used only when we want to send our credentials hidden in secure HttpOnly cookies to which we don't have access to but browser does.
Apparently it is also used when we want to set cookies from response. Link to docs.
responses from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request
Secondly, we also have to add withCredentials on backend to CorsFilter (in Spring boot) otherwise we get CORS error.
CorsConfiguration()
.apply {
allowedOrigins = listOf(uiUrl)
allowedHeaders = listOf("*")
allowedMethods = listOf("*")
allowCredentials = true
}

Related

Not able to receive/set cookies in browser from backend in MERN app with backend hosted on heroku and frontend on netlify

I have a MERN app whose backend is hosted on Heroku and frontend on netlify. I am not able to see the cookies in the browser after deploying the app but it works fine on localhost. I think it is due to different backend and frontend ports, what am I missing, please help
You are correct. Cookies are not cross-domain compatible. If it was, it would be a serious security issue. The easiest way to fix your problem would be to send back the cookie as a res object, and then setting the cookie manually in the frontend.
Take this for example. I'll do this with JavaScript style pseudocode. Don't copy paste this as this most likely wouldn't work right away. This is what you're going to do on the back-end:
// 1. Authenticate the user.
const userData = await authenticateUser();
const userToken = await verifyUser(userData);
// 2. Return the response object.
return response.status(200).json({
status: 'success',
data: userData,
token: userToken,
});
In the front-end:
const response = await axios.post(...); // your API call, will return above object.
// set your authentication token here.
// the 'options' object will contain all possible cookie options, example would be 'secure'.
cookies.set('token', response.data.token, options);
// alternatively, set the cookie in the local storage.
localStorage.setItem('token', response.data.token);
You need to set the cookie accordingly in the front-end.
Further reading: MDN Docs
EDIT: Your question is unclear. First time you talked about cookies, but now you're talking about httpOnly cookies. Please be more specific in your questions.
It is impossible to set httpOnly cookies in React.js if it is cross-domain. React is only responsible for the 'view' of the website. httpOnly cookies are only meant to be set server-side. Client-side JavaScript cannot read or set that specific cookie, but it is able to send it. Unless you have something in your Netlify that can do server-side operations, I don't think that is possible.
Your best bet is to actually just use the same domain.

Vue-cookies with Firebase and Heroku, not being sent

I have a Vue.js project deployed on firebase and a node-express app deployed on Heroku. Now I want to send cookies along with each request to the server using Axios. I am using Axios and cookies are being set using vue-cookies (which are of sameSite: none and secure: true attributes).
In localhost, I can see the cookies in each request in my backend and can access them using req.cookies.session. (The session is my cookie name that is saved on the client-side.)
But in production, I can't see the cookies in the request. What am I doing wrong?
node-express cors
app.use(cors({
credentials: true,
origin: 'https://paid-kickstartu-webapp.web.app',
'Access-Control-Allow-Origin': '*',
}));
Also attaching my screenshots of both Axios configuration and node-express backend for more understanding. Everything is working but cookies are not being sent in the backend from the frontend. In localhost both work as required.
Try this
If you are using Firebase Hosting + Cloud Functions, __session is the only cookie you can store, by design. This is necessary for us to be able to efficiently cache content on the CDN -- we strip all cookies from the request other than __session. This should be documented but doesn't appear to be (oops!). We'll update documentation to reflect this limitation.
Also, you need to set Cache-Control Header as private
res.setHeader('Cache-Control', 'private');
Thank you all for helping. I have solved this problem, what I was doing before was getting the cookie in res body and saving the cookie on the client-side using vue-cookie, So any call to the backend was showing me empty cookies. But now I am setting the cookie header from my backend (node-express) during login and now when I send any further request's I can see the previous cookies that were set in my headers during login.

Cookies not set when nodejs server is not on localhost

I have a ReactJS frontend and a NodeJS backend. The frontend calls the login API from NodeJS it returns a cookie with the JWT token which will be used for other calls. I've tested it and it works when both the frontend and backend are running on localhost.
I've used postman and called the same API. One running on localhost and one running on AWS EC2. Both returns the same response, however, the one running on EC2 doesn't set the cookie. set-cookie header is present on both.
I've included the cors configuration.
var corsOptions = {
origin: ['http://localhost:3001'],
credentials: true
}
app.use(cors(corsOptions));
FOUND THE PROBLEM:
Turns out safari was blocking the cookies. Chrome on iOS is affected by it too. Turning off the option "Prevent cross-site tracking" on safari preferences solved the issue
try to use the full link to send a request to API
axios.post('https://mysite/api/v1/login', {email,password,...})

Cookies not sent on redirect

I am building a react web application with a separate back-end express api that manages all the calls, including passporting and setting cookies. Let's call the back-end service 'api.com' and the front-end service 'react.com'. I'm using passporting with an existing provider (spotify) and after the authorization succeeds, a cookie is set on api.com. The idea is that the user interacts with react.com and requests are made to api.com via a proxy.
If I'm just testing in my browser and I make a call to api.com/resource, the cookie is automatically set. I know this because I've added a bit of logging and also because the requests that require authorization are succeeding via the cookie.
However, when I make calls to api.com from react.com via the proxy, the cookie is not set. Is this expected behavior when proxying? It seems odd that the cookie is set when I call api.com directly, but it is not set when it is redirected. Is there a way around this? My thought would be to communicate the cookie from api.com to react.com, save it there, and send it on all subsequent requests, but that seems overkill. I'm also wondering if maybe I should be setting the cookie on react.com instead of api.com.
I've tried in both Firefox and Chrome, and if it makes a difference, I'm using axios for the requests on react.com.
const request = axios({
method:'get',
url:'/api/resource'
});
This gets proxied as follows (still on react.com), using express-http-proxy:
app.use('/', proxy('api.com', {
filter: (req) => {
return (req.path.indexOf('/api') === 0);
}
}));
But once this hits api.com, any authentication fails, because the cookie is not present.
Any help is appreciated
As far as I have understood your question, I think you're not considering that cookies are set to host name.
So in the first case the hostname is same and its okay, but in the second case the browser's cookies are not set for react.com
So trying to set the cookie on react.com should work.
I would have asked for a clarification using a comment but I don't have enough reputation for that yet.

Sharing a cookie between multiple apps on localhost

My API (localhost:8080) issues cookies for my frontend (localhost:3000). The cookies domains are set to "NULL" on development mode.
I have another small frontend (localhost:9000) on the side. It will be deployed as a subdomain of the frontend in production, so I shouldn't have issue.
In development, I have found no way to request the API from my small frontend, I have no CORS issues but my API throws 401 because the small frontend isn't sending the cookie. The "Send For" attribute is set to "Any type of connection". The cookie is set to expire in a year. I checked in the browser settings, on both ports the cookie is there with the same settings and content.
On the small frontend I can list the cookies on document.cookie but trying to retrieve any value from the cookie using either
function getCookie(key) {
var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
return keyValue ? keyValue[2] : null;
}
getCookie('sid');
OR
$.cookie('sid');
Doesn't work.
Setting the cookie domain to NULL doesn't work.
Setting the cookie domain to localhost doesn't do the trick either and it isn't supported by chrome. (see this) It is supported on FF but I have the same issues
I have tried to set the cookies domain to ".app.localhost" and then set in /etc/hosts
127.0.0.1:8080 api.app.localhost
127.0.0.1:9000 app.app.localhost
127.0.0.1:3000 front.app.localhost
But I couldn't access my apps.
I think I missing something big here.
EDIT:
About the /etc/hosts file
After some digging I found out that ports cannot be specified on ips
However, you can set it up this way:
127.0.0.1 api.app.localhost:8080
127.0.0.1 app.app.localhost:3000
127.0.0.1 app2.app.localhost:9000
I can access and login on my app.app.localhost:3000 with the cookie set to .app.localhost, when I go to app.app.localhost:9000 I can see that there is a cookie containing my sessionId setup with .app.localhost as domain and Any kind of connection.
Yet, same issue as explained above.

Resources