{"resource":{"author":{"id":"h2so9H8jPMmgUKGghoNl","name":"Yomesh Gupta","username":"yomeshgupta"},"content":{"link":null,"difficulty":1,"domain":2,"type":1,"isInternal":true,"body":"In this blog post, we are going to see how can we send multiple cookies to the browser in a Remix powered web app.\r\n\r\n## Problem Statement\r\n\r\nLet us consider the `login` functionality in a web app. Once the user is successfully authenticated, we want to --\r\n\r\n1. Redirect users to their respective dashboard\r\n2. Set the session cookie\r\n3. Set the tracking cookie\r\n\r\n## Setting up Session and Redirection\r\n\r\nWe can use Remix's inbuilt utilities to manage the session and redirect.\r\n\r\n```js\r\nimport { createCookieSessionStorage, redirect } from \"remix\";\r\n\r\nconst storage = createCookieSessionStorage({ ... });\r\n\r\nexport async function createUserSession(userId) {\r\n  const session = await storage.getSession();\r\n  session.set(\"userId\", userId);\r\n\r\n  return redirect('/dashboard');\r\n}\r\n```\r\n\r\nIn the function `createUserSession`, we get the session, set the `userId`, and redirect the user to the dashboard route.\r\n\r\n## Setting Cookies\r\n\r\n1. The HTTP helper `redirect` provided by Remix takes an object as the second parameter where we can set different options like `status`, `headers`, and so on. Let us use that to send the `Set-Cookie` header with the session cookie as the value.\r\n\r\n```js\r\n...\r\n\r\nreturn redirect('/dashboard', {\r\n  headers: {\r\n    'Set-Cookie': await storage.commitSession(session)\r\n  }\r\n});\r\n```\r\n\r\nWe are now redirecting the user to the dashboard and also setting the `session` cookie to keep them logged in.\r\n\r\n2. Now, we want to set the tracking cookie. We can try doing the same thing as the session cookie and set another `Set-Cookie` header.\r\n\r\n```js\r\n...\r\n\r\nreturn redirect('/dashboard', {\r\n  headers: {\r\n    'Set-Cookie': await storage.commitSession(session),\r\n    'Set-Cookie': 'user_tracking_id=e8bb43229de9; Max-Age=2592000; Path=/; Secure; SameSite=Lax'\r\n  }\r\n});\r\n```\r\n\r\nHowever, the above code snippet introduces a new problem. The most recent `Set-Cookie` key would overwrite the previous ones.\r\n\r\n## Resolving Same Header Key Issue\r\n\r\nWe can resolve the above-mentioned problem by using the [Headers()](https://developer.mozilla.org/en-US/docs/Web/API/Headers/Headers) constructor. We can create a new instance of the Headers object, append keys to it, and send it to the client.\r\n\r\n```js\r\n...\r\n\r\nconst headers = new Headers();\r\nheaders.append(\"Set-Cookie\", await storage.commitSession(session));\r\nheaders.append('Set-Cookie': 'user_tracking_id=e8bb43229de9; Max-Age=2592000; Path=/; Secure; SameSite=Lax');\r\n\r\nreturn redirect('/dashboard', {\r\n  headers,\r\n});\r\n```\r\n\r\nThis resolves our problem and both cookies would be stored in the user browser! 🙌\r\n\r\nI hope this blog post helped you in some way. Please do share it and show our content much-needed love! 😄\r\n\r\nIf you feel something is missing/wrong/improvement is possible then feel free to reach out -- [Devtools Tech](https://twitter.com/devtoolstech) and [Yomesh Gupta](https://twitter.com/yomeshgupta)\r\n","languages":[],"editorConfig":{}},"stats":{"views":16714,"used":0,"likes":0},"description":"","published":true,"isActive":true,"tags":["","javascript","cookies","remix run","js framework","web fundamentals","frontend","coding","headers","http","redirection","tracking","session"],"slug":"how-to-send-multiple-cookies-in-a-remix-powered-web-app---rid---ndORf220mRIUxvoJPvtb","isPremium":false,"categories":[],"requires":[],"_id":"6206280b1641361c7c65a721","title":"How to Send Multiple Cookies in a Remix Powered Web App?","resourceId":"ndORf220mRIUxvoJPvtb","createdAt":1644570635295,"modifiedAt":1644571041887},"currentUser":null,"isOwner":false,"recommendations":{"questions":[{"_id":"5fce64866d3cda64e470c420","content":{"languages":["javascript"],"difficulty":4},"tags":["javascript","new operator","frontend","js fundamentals","frontend fundamentals","interview concepts"],"slug":"what-would-be-the-output-of-the-following-code-snippet-es6-classes---qid---212yoqEY48ZvHTpK2zQI","title":"What would be the output of the following code snippet? [ES6 Classes]","questionId":"212yoqEY48ZvHTpK2zQI"},{"_id":"5ea9ac27dae82663ed99f7d8","content":{"difficulty":1,"languages":"html"},"tags":["html","javascript","event handling","frontend","interview questions"],"title":"What would be the output on the button click? (Event Handling)","questionId":"Iupnm02c9CKHJhxL2ah9","slug":"what-would-be-the-output-on-the-button-click-event-handling---qid---Iupnm02c9CKHJhxL2ah9"},{"_id":"646dcf2fd12c1e240202f234","content":{"languages":["javascript","typescript"],"difficulty":1},"tags":["problem solving","frontend","code","interview","ui","ux","lodash","polyfills","coding","tooling","frontend coding challenge","interview questions","leetcode"],"slug":"implement-a-function-to-generate-a-range-of-numbers-or-range-i-or-javascript-interview-question-or-lodash-polyfills---qid---ZfQeEBCKkGiCvLpYqcLt","title":"Implement a function to generate a range of numbers | Range I | JavaScript Interview Question | Lodash Polyfills","questionId":"ZfQeEBCKkGiCvLpYqcLt"},{"_id":"6015b6a04ddda40a64cf14f8","content":{"languages":["javascript","typescript"],"difficulty":4},"tags":["javascript","frontend","arrays","interview","recursion","prototype chain","advanced javascript","arrow functions"],"slug":"how-to-create-a-flat-version-of-a-deeply-nested-array-programming-interview-question---qid---l5Qx4LJ7glelCkIxQjXB","title":"How to create a flat version of a deeply nested array? [Programming Interview Question]","questionId":"l5Qx4LJ7glelCkIxQjXB"},{"_id":"646cea30d12c1e240202e0e1","content":{"languages":["javascript","typescript"],"difficulty":2},"tags":["javascript","frontend","coding","devtools tech","ui","ux","egghead","frontend masters","tooling","js questions","frontend interview questions","frontend problems","frontend problem solving","getElementsByTagName","dom manipulation"],"slug":"how-to-implement-getelementsbytagname-or-frontend-problem-solving-or-javascript-interview-question---qid---1Z2H3eRWdCqV4XU4FRzV","title":"How to implement getElementsByTagName? | Frontend Problem Solving | JavaScript Interview Question","questionId":"1Z2H3eRWdCqV4XU4FRzV"}],"resources":[{"_id":"69a52acc92f33c7d8a9f6107","content":{"difficulty":4,"domain":1,"type":2,"isInternal":false,"languages":[]},"tags":["javascript","ui","ux","devtools tech","tutorial","rendering","coding"],"slug":"how-react-ssr-actually-works-without-frameworks---rid---8decG2azJUycVwuG2WQE","title":"How React SSR Actually Works (Without Frameworks)","resourceId":"8decG2azJUycVwuG2WQE"},{"_id":"6a12e5104b3e6d922c54a0cf","content":{"difficulty":1,"domain":1,"type":1,"isInternal":true,"languages":[]},"tags":["javascript","ui","ux","devtools tech","coding","frontend"," web performance"],"slug":"reducing-image-bytes---rid---eoeW8SDZdwwNWBtFqfOh","title":"Reducing Image Bytes","resourceId":"eoeW8SDZdwwNWBtFqfOh"},{"_id":"6a12f6954b3e6d922c54a4bb","content":{"difficulty":1,"domain":1,"type":1,"isInternal":true,"languages":[]},"tags":["javascript","ui","ux","devtools tech","prioritising critical images","web performance"],"slug":"prioritising-critical-images---rid---BlV5X4YylAW61dYwFmyG","title":"Prioritising Critical Images","resourceId":"BlV5X4YylAW61dYwFmyG"},{"_id":"6a47f2cd9d0d3621161949c7","content":{"difficulty":1,"domain":1,"type":1,"isInternal":true,"languages":[]},"tags":["javascript","ui","ux","devtools tech","coding","frontend","challenges","web performance"],"slug":"optimising-web-performance-for-low-powered-devices---rid---v6b2cw5kovr4LEqgNImK","title":"Optimising Web Performance for Low-Powered Devices","resourceId":"v6b2cw5kovr4LEqgNImK"},{"_id":"5f1dd74dcbec5f7ffc0c2fac","content":{"difficulty":2,"domain":3,"type":1,"isInternal":true},"tags":["node.js","express","rest","api","framework","backend","tools","devtools","framework development","build express"],"slug":"build-your-own-expressjs-or-part-3---rid---6mHfnu0fQoPw4RBpexRV","title":"Build your own expressjs | Part 3","resourceId":"6mHfnu0fQoPw4RBpexRV"}]}}