My Cookie is not setting. Works in Thunder Client. JavaScript React Node.js - express

Firstly this is my first question on here so if I missed anything or did something wrong let me know. My Cookie is not showing up in the application cookies and not being sent to back end along with request. The cookie holds a refresh JWT. I can tell its being sent along with the response from backend as it shows up in cookies under network tab.
sending cookie
res.cookie("jwt",refreshToken,{
httpOnly:true,
sameSite: "none",
secure:false,
maxAge:24*60*60*1000,
})
res.status(200).json({roles,accessToken,id:foundUser.id})
Front end request
const response =await axiosPrivate.post ("https://my
backend/auth",JSON.stringify({userName,password}),
{headers:{'Content-Type':'application/json'},
withCredentials:true})
cookie in res from above request
request to send cookie
const response = await axios.get('https://my backend/refresh',{ withCredentials:true})
I have tried removing all headers on cookie same result. Tried hosting the project so its on HTTPS same result tried sending cookie from unhosted backend same result.

Related

How to handle JWT refreshing on server side (Next.js or any other)

I have two cookies being stored: JWT and refresh token, both are httponly; path=/, so they are send on all requests, including the API (which doesn't use Bearer, but instead reads the JWT directly from the cookies).
The implementation is as usual, the JWT is short lived, and the refresh token is used to get a new one. The refresh token is rotating and after used is invalidated.
On the client, refreshing the token is no issue. When a 401 is returned by the API a call is made to /auth/refresh-token and the request is retried.
On the server however, (e.g. on getServerSideProps) it seems to be quite difficult to refresh the JWT. What I have attempted is to create a custom server and a middleware that checks when a JWT is expired and attempts to refresh it.
I can think of two issues with that, first is that the custom server is called on every resource, that includes all json, js, static files, etc... that Next.js serves. When two requests are made with the same tokens (I can handle this when making API calls, but Next.js also sends requests to the server and I cannot control those):
1. Two requests with expired JWT are sent to the server
2. The back-end receives the requests and on both determines it needs to refresh the token
3. Eventually one of the requests will complete, invalidating the refresh-token
4. The other request now has an invalidated refresh token and cannot get a new JWT
Second issue, what if the user doesn't receive the response, scenario:
1. A request with an expired JWT is sent
2. The back-end refreshes it and sets the new cookies
3. The back-end then has to read lots of data from a database which takes a few seconds
4. User closes the page before receiving the response
5. At this point the user has an invalidated refresh token and an expired JWT because the response with the new cookies was never received
How are these cases usually handled? It seems like it would be a common issue with rotating refresh tokens, but I couldn't find anything useful on this online.
You can follow this practice.
Save refresh token in the http-only cookie
No need to save JWT in the cookie for better security and keep it in the response of refresh token as well as login endpoint.
Save JWT expiry in a normal cookie
Call refresh token endpoint to get new JWT when expiry token is not present or getting 401 error.
In getServerSideProps also you can call the refresh token endpoint always as you don't need to persist JWT anywhere.
You may need to get the cookie from req.headers.cookie and pass it in the header when you are calling the refresh token endpoint from the server.
//inside getServerSideProps
const browserCookie = req.headers.cookie;
const refreshJWTTokenResponse: any = await refreshJWTToken(browserCookie);
//service call
export async function refreshJWTToken(refreshTokenCookie: any): Promise<{}> {
let headers = new Headers();
headers.append("Cookie",`${refreshTokenCookie}`);
const options = {
method: 'POST',
headers: headers,
credentials:'include',
};
...
}

Is it possible to set an HttpOnly Cookie from one domain to another subdomain

I originally posted this question here: https://security.stackexchange.com/questions/255737/is-it-possible-to-set-an-httponly-cookie-from-one-domain-to-another-subdomain
Please keep in mind that this question is specific to cookies with the HttpOnly flag set to true.
I am pretty sure that the answer to my question is no, but I have been have a hard time finding an answer through official documentation or other posts here. Here is simple use case for some context:
Python backend web application (api.domain.com)
Frontend JavaScript SPA (app.domain.com)
post requests to api.domain.com/api/auth/login/ made from app.domain.com using axios with the correct username and password return a response with an access JWT token in the body and the response sets a refresh cookie with an HttpOnly flag [should fail, since I believe that the cookie cannot be set on app.domain.com from an API request to api.domain.com? -- this is my question]
the access token is stored in memory and passed with each API request
requests made to api.domain.com/api/auth/refresh/ are sent on a schedule to refresh the short-lived access token.
I typically host the frontend app and backend app on the same subdomain (app.domain.com) and do path-based routing with something like CloudFront or nginx, and this works well. For example, all requests starting with /api/* are sent to the backend, and all other requests are sent to the frontend app. Trying to use a separate subdomain for the API seems to fail no matter what options I use for setting the cookie on the server.
Can someone help me confirm that it is in fact not possible to set an HttpOnly cookie on a subdomain like app.domain.com from an API request hosted on api.domain.com? It would be great if anyone can also help me find where this could possibly be found in official documentation.
Searching for set httpOnly cookie across subdomains, I haven't found anything directly relevant. I also didn't find anything in these resources that directly answers my question:
https://owasp.org/www-community/HttpOnly
https://learn.microsoft.com/en-us/previous-versions//ms533046(v=vs.85)?redirectedfrom=MSDN
This is possible. In fact I just did it.
On your frontend, using Axios:
const baseURL = 'https://api.example.com';
const api = axios.create({
baseURL,
withCredentials: true,
});
On your backend, using Express:
app.use(
cors({
origin: 'https://www.example.com',
credentials: true,
}),
);
app.post('/login', async (req, res) => {
res.cookie('someCookie', someCookieValue, {
secure: true,
domain: 'example.com',
httpOnly: true,
});
});

cookie sets in postman but not in browser on localhost

I have an issue with cookies setting in postman when I make a post request to my route to login but unfortunately when I use the same info to login via my vue frontend I don't get a set cookie header in my browser or a token but rather it just returns and API key with a value....
not sure if anyone can help explain why this might be the case. Does postman run on localhost itself by default or do they use their own servers to route requests? just wondering if maybe that's the issue?
here's the code I am using to touch the endpoint in my view endpoint
Note: I have a separate axios file with the root url so the route only shows as /login just to clarify
async handleSubmit(){
const response = await axios.post('/login', {
email: this.email,
password:this.password
});
console.log(response)
}
inside my console when logging it only returns an api key instead of a session id.
trying to dig around the postman docs to see if I can somehow use this key to get a session ID?
https://learning.postman.com/docs/sending-requests/authorization/#api-key
any help is greatly appreciated :)

AXIOS: Cookie value changes on every request

Im working on a login page,
I have 2 api:
api1 = for authentication of credential
api2 = for getting user info
the first request is fine, but the second request always fails, when I checked the response headers the PHPSESSID on set-cookie changed.
I use axios.defaults.withCredentials = true but didn't work
not sure what to do on this.
I hope you can help me.
thanks

axios api authentication headers jwt and security

Two questions here:
I was not able to pass in a post request using axios and authorization headers as such:
axios.post('http://localhost/dashboard', {headers: { 'Authorization': 'JWT xxxxxx' }})
But I was able to get it to work with a preset: axios.defaults.headers.common['Authorization'] = 'JWT xxx'
Am I missing something as to why the headers parameter was sending the "headers" as a data payload instead of as an actual header?
Once I generate a JWT from my login page, on each page request after that I am only showing the page if the response.status is 200. Is this the correct way to redirect someone back to a login page if their jwt is fake or invalid for accessing the page?
The flow is:
/login for user to get JWT
immediately directed to /dashboard but before they are an api call is made to /dashboard using the JWT and if status code is 200, then the /dashboard page is shown. Is this correct or should I be implementing something more than just a 200 code?
Am I missing something as to why the headers parameter was sending the "headers" as a data payload instead of as an actual header?
Because you're passing the headers as the data payload. I suggest reading the axios docs for axios.post()
It's common to automatically refresh the JWT instead of logging the user out. Depends on your security requirements. For ex., if you were a bank, it's better to log the user out than to auto refresh the JWT.
Instead of checking for 200, check if the status is 403 (or whatever status your backend returns for an invalid JWT). If your backend errors (500), or receives a bad request (400), it's not relevant to an invalid JWT and you'd be logging the user out for nothing.