Sveltekit newly created cookie is not showing in the hook's handle function - cookies

Summary
Once set-cookie header is sent in a response it takes another request before the cookie is visible in handle() function in the hooks.ts file.
Example
User POSTs username & password to the login endpoint;
Enpoint responds with set access_token cookie header;
User should be redirected to a protected page. (FAILS)
It fails because auth guard checks if the cookie exists, but it can't be seen from a code side at this point, only in the browser end.
Refresh the page
User is now able to be redirected to a protected page.
Minimal reproduction
It has dummy login/logout functionality & protected user profile. There are also server side console logs which shows that cookie lags to be recognised in a hook.

As mentioned in the comments, your server returns the HTTP status code 200 which does not redirect the Client after the Login. The browser assumes it is already at its final destination due to the status code.
In this case, best practice is to use the status code 302: Wikipedia
Modified /src/routes/auth/login.ts
import * as cookie from 'cookie';
export const post = (request) => {
return {
status: 302,
headers: {
location: '/',
'set-cookie': `${cookie.serialize('token', 'VALUE_OF_THE_COOKIE')}; path=/; HttpOnly`
}
}
};
export const del = (request) => {
return {
status: 302,
headers: {
location: '/',
'set-cookie': `${cookie.serialize('token', '')}; path=/; HttpOnly; maxAge: 0`
}
}
};

Related

Not able to set cookie in browser with Deno Oak

I am trying to set up Authentication with Deno, Oak and JWT.
Objective:
Send cookie with jwt token in the response.
Set cookie in the browser
Use the cookie for subsequent requests.
Route: Cookie being set
export const getUsers = async ({ response, cookies }) => {
const users = await userCollection.find().toArray();
await cookies.set("token", "1234567890", {
sameSite: "lax",
});
response.body = users;
};
handling the Cors issue
app.use(
oakCors({
credentials: true,
origin: /^.+localhost:(3000|4200|8080)$/,
})
);
Response headers has the cookie but the same is not set in Application --> Cookies.
Please help me understand this issue.
using ctx.cookies.set is how you set a cookie in Oak, have in mind that by default it's httpOnly. Your browser might not show it in that case or you're looking in the wrong place.
From the screenshot we can see that Oak is setting the cookie correctly in the response headers:
token=1234567890; path=/; samesite=lax; httponly
To check that the cookie is set correctly, just add:
console.log(await ctx.cookies.get('token'));
And you'll see that in subsequent requests will log 1234567890 correctly.
Since you're mentioning CORS I suspect that you're looking the cookie to be present in the wrong domain, you should be looking for the cookie in:
localhost:8000 (server setting the cookie)
And not in your front end domain:port
So, if you issue the request from: http://localhost:3000 to http://localhost:8000, when you're in :3000 there will be no cookie present in Application > Cookies > http://localhost:3000, but it'll be in Application > Cookies > http://localhost:8000

fetch() Not setting cookie despite `Set-Cookie` header

My backend-api written in Node and Express.js sets a cookie using res.cookie:
Router.post('/login', async (req, res) => {
const email = req.body.email;
const password = req.body.password;
try {
let result = await sqlite.login(email, password);
res.cookie('token', result, {
'maxAge': 3600 * 1000
});
res.send({
'token' : result
});
} catch (err) {
res.send(err);
}
});
I can make a request to this route, and I do notice the Set-Cookie header is set on the response object within Chrome developer tools:
Set-Cookie: token=[...]; Max-Age=3600; Path=/; Expires=Mon, 11 Jul 2022 14:47:08 GMT
However, document.cookie is never set by the browser. From my searching, most people say to specify the credentials field as same-origin. I have done this and it made no change. My cookie is NOT being set as HttpOnly, so I am unsure why it's being set by the browser.
Here is where I call the /login route:
async login(email, password) {
let response = await fetch(apiURL + '/login', {
'method' : 'POST',
'headers' : {
'Content-Type' : 'application/json',
'Accept' : 'application/json'
},
'credentials' : 'same-origin',
'body' : JSON.stringify({
'email' : email,
'password' : password
})
});
return await response.json();
}
A token is successfully returned in the response, but again document.cookie returns an empty string ''.
From searching this problem, most of the issues seem to suggest that same-origin should fix the issue but it is not the case for myself. Another thing of note is that httpOnly cookies won't show in the browser, but I know that the cookies I am sending are not HttpOnly.
I am using Google Chrome version 103.0.5060.114.
If I set credentials to include, I get a CORS error:
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
I was able to get it working with the following changes:
When initializing npm package cors, specify some options:
app.use(cors({ credentials: true, origin: 'http://lvh.me:3001' }));
The origin must include the http:// prefix as well as the correct port. Once that was done, set credentials to include when calling fetch() and it should work fine.

Postman - How to use pm.sendRequest without any cookies?

In my Postman collection, I have a pre-request script that ensures I have a valid JWT token available for authentication. It looks similar to the following (I have removed the logic of checking expiration and only fetching a new token if needed):
function get_and_set_jwt() {
let base_url = pm.environment.get("BASE_URL")
pm.sendRequest({
url: base_url + '/api/auth/',
method: 'POST',
header: {
'content-type': 'application/json',
'cookie': ''
},
body: {
mode: 'raw',
raw: JSON.stringify({ email: pm.environment.get("USER_EMAIL_ADDRESS"), password: pm.environment.get("USER_PASSWORD") })
}
}, function (err, res) {
let jwt = res.json().token
postman.setEnvironmentVariable("JWT", jwt)
});
}
get_and_set_jwt();
I am attempting to set 'cookie': '' so that the request from this script will be made with no cookies. The backend I am working with sets a session cookie in addition to returning the JWT, but I want to force all future requests (when I need to renew the JWT) to not include that session information.
Unfortunately, if I check the Postman console, I see that the requests are still being sent with the cookie header, and the session cookie that was set by the earlier response. I have even tried overriding it by setting 'cookie': 'sessionid=""', but that just yields a request that includes two session ids in the cookie header (it looks like sessionid=""; sessionid=fasdflkjawew123sdf123;)
How can I send a request with pm.sendRequest with either a completely blank cookie header, or without the header at all?

Nuxt.js and forwarding cookie to backend

I have site on nuxt.js (example.com) and backend on PHP (example.com/api/).
Some page get data from /api/some:
asyncData() {
return axios.get("http://example.com/api/some").then((response) => {
return response.data;
});
},
In PHP-handler of "/api/some" I write to the log recieved cookies.
If I go to some-page by link (browser ajax-request) cookies exist.
If I refresh page (server-side rendering) then cookies is empty.
Cookie reach to nuxt (context.req.headers.cookie is not empty) but don't transfer to backend.
How I can fix it?
Sorry, it work for axios.
const headers = {};
if (context.req) {
headers.Cookie = context.req.headers.coookie;
}
return axios({
url: url,
method: "get",
headers: headers,
}).then(/* ... */);

Accessing cookie with Angular or Javascript

I created an API /user/auth where I can send using POST a Json object like:
var user = {"username":"alex", "password":"m"}
$http(
{
method: 'POST',
url: '/api/v1/user/auth',
data: user,
}
).
success(function(data, status, headers, config) {
console.log(data)
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
The response from Django is the following:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type,*
Access-Control-Allow-Methods:POST,GET,OPTIONS,PUT,DELETE
Access-Control-Allow-Origin:*
Content-Language:fr
Content-Type:application/json
Date:Fri, 30 Aug 2013 15:22:01 GMT
Server:WSGIServer/0.1 Python/2.7.5
Set-Cookie:sessionid=w63m0aoo8m3vfmvv0vk5d6w1708ftsrk; Path=/
Vary:Accept, Accept-Language, Cookie
So Django returns a good cookie but I don't know why, Chrome doesn't set this cookie in Resource.
The request is sent from 127.0.0.1:8000 to 127.0.0.1:8080; I use this middleware to handle CROS requests and I also set:
SESSION_COOKIE_HTTPONLY = False
The problematic line is:
Access-Control-Allow-Origin: *
The credential request doesn't work with a wildcard allow origin. You have to specifically set the name, like :
Access-Control-Allow-Origin: http://127.0.0.1:8080
You can find more information here:
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#Requests_with_credentials
Ok thanks to Bqm link to mozilla I finally found why the cookie was not set.
Indeed you need to set in the header you sent:
Access-Control-Allow-Credentials: true
In Angular this is done with this method:
$http(
{
method: 'POST',
url: '/api/v1/user/auth',
data: user,
withCredentials: true
}
)
Once your backend will answer with a setCookie, the browser will then be able to set the cookie in your browser.