Sam King
Sam King

Reputation: 41

Unable to send cookies from Express.js backend to Next.js 14 frontend

Here's my setup:

I'm unable to send cookies with res.cookie from my backend. Although my passport.js is able to send a session.id in some weird function.

Although I know its role, if anyone can shed some light on functions in cookie responses that's cool.

Not to worry if not, i'm more worried why I cant send my cookies!

Here's my some helpful code regarding the issue:

// Cors setup

  app.use(cors({
    credentials: true,
    origin: 'http://localhost:3000'
  }))

// Frontend serverside api caller with redirects setup in next.config.js

import ky from "ky"
import { cookies } from "next/headers"

const cookieStore = cookies()

export const serverSideApi = ky.extend({
  prefixUrl: `${process.env.CLIENT_URL ?? "http://localhost:3000"}/api`,
  credentials: "include",
  headers: {
    cookie: cookieStore.toString(),
  },
  cache: "no-store"
})

//Serverside attempt to set cookie response

async function findUserBySession(req, res) {
  const userId = req.session.passport?.user
  const boardsCount = await KanbanBoard.count({ where: { ownerId: userId } })
  const user = await User.findByPk(userId, {
    include: [{
      model: Team,
      as: 'teams',
      through: { attributes: [] },
      attributes: ['id', 'name', 'profilePicture']
    }]
  })

  if (!user) {
    return res.sendStatus(404)
  }
  res.cookie('boardsCount', boardsCount || 0);
  return res.json(user)
}

//Layout.js setup

import "@scss/styles.scss"

import { cookies } from "next/headers"
import { Manrope } from "next/font/google"
import { serverSideApi } from "@app/serverSideApi"
import StoreProvider from "@app/StoreProvider"
import DashboardHeader from "@components/client/ClientHeader"
import DashboardSidebar from "@components/client/ClientSidebar"
import Toast from '@components/Toast'

const manrope = Manrope({ subsets: ["latin"] })

export const metadata = {
  title: 'Client Dashboard',
  description: 'Generated by create next app',
}

export default async function DashboardLayout({ children }) {
  const user = await serverSideApi
    .get("users/me").then((res) => res.json())
    console.log(user)

  let team = null 
  if (user.currentTeamId) {
    team = await serverSideApi
      .get(`teams/${user.currentTeamId}`).then((res) => res.json())
  }

  const cookieStore = cookies()
  console.log(cookieStore)

  return (
    <html lang="en">
      <body className={manrope.className}>
        <StoreProvider user={user} team={team}>
          <div className="dashboard-wrapper">
            <DashboardSidebar />
            <div className="dashboard-wrapper__body">
              <DashboardHeader />
              <main>
                {children}
              </main>
            </div>
          </div>
          <Toast />
        </StoreProvider>
      </body>
    </html>
  )
}

// Console.log response for cookieStore

project-22/client:dev: f {
@project-22/client:dev:   _parsed: Map(1) {
@project-22/client:dev:     'connect.sid' => {
@project-22/client:dev:       name: 'connect.sid',
@project-22/client:dev:       value: 's:7TQyl4xxyWV7dtT1K8Q_LRXCuhryx_3N.svEY2TEf3PlY3j8oLFS6ukSYoiotls77cqmpJbCMwzQ'
@project-22/client:dev:     }
@project-22/client:dev:   },
@project-22/client:dev:   _headers: HeadersList {
@project-22/client:dev:     cookies: null,
@project-22/client:dev:     [Symbol(headers map)]: Map(0) {},
@project-22/client:dev:     [Symbol(headers map sorted)]: null
@project-22/client:dev:   }
@project-22/client:dev: }

Once again I'm wondering why I keep getting null in the cookies response when I set it with res.cookie? I would like to set flags in there.

(the sid is set from my passport)

Thanks!

Upvotes: 0

Views: 909

Answers (2)

Jebali Mazen
Jebali Mazen

Reputation: 1

Remove the samesite:none attribute. Worked fine for me.

Upvotes: 0

Sandeep M
Sandeep M

Reputation: 350

The error could be because there are two different origins. Since the nodejs is on 4000 and browser is on 3000, there is a difference in the requests generated. You can not set cookies for differnent domains.

If the cookies are avaialble on postman and not on browser, it is because the request is directly hit on the 4000. If you can open a webpage on port 4000, then the cookies might be set.

Also you can try with the two changes

  1. Remove the samesite:none attribute
  2. Try withCredentials: true attribute.

Reddit Answer that helped

Upvotes: 1

Related Questions