2

I'm facing an issue since svelte last update. When I try to add multiple set-cookie in one request, only the first one is executed. I'm searching for 5 days, and I didn't find any solution.

Config

Frontend - SvelteKit v1.0.0-next.234 Backend - Strapi 3.6.1 (v4.x.x not working with mongoDb if I understand well) Db - mongo

What worked before Svelte update

I call my login endpoint with my credentials (username, password), and wait for the jwt token response. When I receive it, I put it within other elements in my http request headers. In the hook.js file, I parse this header cookie and add it to my request.locals. Therefore, I can use my request locals within the getSession() method of the hooks.

Login.json.js endpoint

... all the query logic
const user = await login();
// ==> I get the jwt token

const cookieOptions = {
 Secure: secure ? 'Secure;' : '',
 httpOnly: true,
 sameSite: sameSite,
 path: "/",
 maxAge: 60 * 60 * 24 * 7
}
const setUsername = cookie.serialize(`${COOKIE_NAME}`, user.user.username, cookieOptions);
const setJwt = cookie.serialize("jwt", user.jwt, cookieOptions);
const setCompId = cookie.serialize("_cId", user.user.company._id, cookieOptions); 


// what worked before, but stop working after svelte framework update
const headers = {        
 'Set-Cookie': [setUsername, setJwt, setCompId]
}

// what I do know to find a way to solve it
let headers = new Headers();
headers.append('Set-Cookie',setUsername);
headers.append('Set-Cookie',setJwt);
headers.append('Set-Cookie',setCompId);

// the response
return {
  body: {
   user
  },
 headers,
 status: 200
 }

I've tried to put a plain text cookie, something like this :

cookiename=myUserName; Max-Age=604800; Path=/; HttpOnly; SameSite=Strict, jwt=xxx.xxx.Xxx; Max-Age=604800; Path=/; HttpOnly; SameSite=Strict, _cId=sjckjsdhfjkqsdhfjk; Max-Age=604800; Path=/; HttpOnly; SameSite=Strict

Only the first cookie is set in the header and in the browser.

hook.js

In my hook file, I had to change the object received by the handle function du to Svelte update

From this

export async function handle({request,resolve}){
 const cookies = cookie.parse(request.headers.cookie || "");
...
}

To this

export async function handle({event,resolve}){
 let cookies = event.request.headers.get("cookie")
...
}

The problem is that I only have one cookie value instead of 3.

I didn't found the solution. I think I can pass all my arguments within the first cookie value, in my login response, but, I think it's not a good idea.

I'm asking for help, because I can't move on my project. My dashboard pages call depends on these 3 elements gathering first.

Thank you all

update 1

I've changed the code has suggested by Thommas

const headers = new Headers()
headers.append('Set-Cookie', [setUsername, setJwt, setCompId].join(','))

When I console.log the headers it's ok, I get my 3 elements separated with a comma.

console.log(headers.get('Set-Cookie'));
// => result string : 
/*
MYCOOKIENAME=ItIsOk; Max-Age=604800; Path=/; HttpOnly; SameSite=Strict,jwt=xxx.xxxx.xxxx.xxxx.Xxx.etc...; Max-Age=604800; Path=/; HttpOnly; SameSite=Strict,_cId=ItIsOk; Max-Age=604800; Path=/; HttpOnly; SameSite=Strict
*/

But, when I look at the request headers in the hooks.js, I still get the first one.

console.log("==>\n",event.request.headers,"\n<==\n")

// result 
{
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7',
  'cache-control': 'no-cache',
  connection: 'keep-alive',
  cookie: 'MYCOOKIENAME=ItIsOk',
  host: 'localhost:3000',
  pragma: 'no-cache',
  referer: 'http://localhost:3000/login',
  'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"',
  'sec-ch-ua-mobile': '?0',
  'sec-ch-ua-platform': '"macOS"',
  'sec-fetch-dest': 'document',
  'sec-fetch-mode': 'navigate',
  'sec-fetch-site': 'same-origin',
  'sec-fetch-user': '?1',
  'upgrade-insecure-requests': '1',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
} 

May be my return object is wrong.

return {
 body: {
  user
 },
 headers,
 status: 200
 }
}

I you have any idea ! I'll continue working on this issue, because I totaly blocked !

FabienC
  • 53
  • 1
  • 7
  • 2
    Have you tried `const headers = new Headers({ 'Set-Cookie': [setUsername, setJwt, setCompId] })`? [234](https://github.com/sveltejs/kit/pull/3384) had breaking changes in the way you access headers, but not in what type of values can be set, so I'm surprised you wouldn't be able to set multiple cookies at once. – Thomas Hennes Jan 26 '22 at 10:01
  • Thank for the reply. Nothing changed. I still get one cookie in the request.hearders – FabienC Jan 26 '22 at 12:08
  • Did this comment `// what I do know to find a way to solve it` mean that `headers.append(...)` does work for you? – kenset Jan 26 '22 at 14:49
  • No, it's not working. I still have one cookie – FabienC Jan 26 '22 at 22:49

3 Answers3

1

This was discussed in

https://github.com/sveltejs/kit/issues/3460

you can use response.headers.append(headerName, headerValue) to add a header without overwriting existing ones. Just call this for every set-cookie you need.

Jan Nitschke
  • 143
  • 3
0

According to Is it possible to set more than one cookie with a single Set-Cookie?, Set-Cookie allows a comma-separated list of cookie declarations.

Onboarding the recent breaking changes made to SvelteKit in v1.0.0-next.234, you should then be setting multiple cookies this way:

const cookieOptions = {
 Secure: secure ? 'Secure;' : '',
 httpOnly: true,
 sameSite: sameSite,
 path: "/",
 maxAge: 60 * 60 * 24 * 7
}
const setUsername = cookie.serialize(`${COOKIE_NAME}`, user.user.username, cookieOptions);
const setJwt = cookie.serialize("jwt", user.jwt, cookieOptions);
const setCompId = cookie.serialize("_cId", user.user.company._id, cookieOptions); 

const headers = new Headers({        
 'Set-Cookie': [setUsername, setJwt, setCompId].join(',')
})

Thomas Hennes
  • 9,023
  • 3
  • 27
  • 36
  • Thanks for your reply, but, nothing changed. I still get only the first cookie in the headers. – FabienC Jan 27 '22 at 23:04
  • I've update my question with your suggestion. Do you think I should post an issue on Svelte gît repo? – FabienC Jan 28 '22 at 15:15
  • Anyt update on how to set more than one cookie in hooks headers? I'm facing this problem and can't figure out a way to fix it. – Marco Mar 24 '22 at 17:05
0

I tried to set a couple of cookies and redirect on a successful request. Jan Nitschke's discussion link was useful. But below worked for me better

import * as cookie from 'cookie';
const token_cookie = cookie.serialize("token", json_res["token"], {
        path: '/',
        httpOnly: true,
        sameSite: 'strict'
})
 
    
return {
      status: 303,
      headers: {
          'set-cookie': [token_cookie, another_cookie],
          'location': '/',
      }
};

I believe you can add more than two, but I had to use only two.

here's the reference

hez
  • 21
  • 5
  • Svelte last update changed everything. Now I'm not using hooks.js file to set header cookies. I use it in my login +page.server.js file. – FabienC Sep 01 '22 at 14:35
  • @FabienC I use that too. Have you figured out a way to set a global state (when logged in) to know user data on the front end? They seem to be insulated. I tried a writable but it sets it on the server itself. – hez Sep 01 '22 at 21:33