Add set method to cookies function in Server Components #49843
Replies: 19 comments 45 replies
-
Any updates on this? |
Beta Was this translation helpful? Give feedback.
-
I created this package to solve this problem: 'use client';
import { useCookies } from 'next-client-cookies';
const MyComponent = () => {
const cookies = useCookies();
return (
<div>
<p>My cookie value: {cookies.get('my-cookie')}</p>
<button onClick={() => cookies.set('my-cookie', 'my-value')}>
Set cookie
</button>
{' | '}
<button onClick={() => cookies.delete('my-cookie')}>Delete cookie</button>
</div>
);
}; It's fully supported both by client components, SSR and server components. See more details on the package readme. |
Beta Was this translation helpful? Give feedback.
-
@leerob Could you perhaps shed some insight on what was the reasoning behind this decision/constraint? |
Beta Was this translation helpful? Give feedback.
-
Hum... so what is the recommended way to set a cookie in a server component? // (some-route)/page.tsx
import { redirect } from 'next/navigation';
export default async function Page({ searchParams }) {
const result = await getSomeData(searchParams);
if (result.something) {
// How can i set a cookie here before the redirect?
redirect('/other-page');
}
return <MyPageComponent />
} @rauchg Can you elaborate on this example? using the actions and following the docs I could not find a way to do it that seemed right |
Beta Was this translation helpful? Give feedback.
-
I've added a FAQ on this: https://nextjs.org/docs/app#how-can-i-set-cookies
|
Beta Was this translation helpful? Give feedback.
-
For a simple way to refresh JWT on server side while respecting the FAQ.
You can manipulate serverside cookies only by Server Actions, Middleware, or Route Handlers. But at the same time you can't access your database in Middleware while it's neccessary for validating the refresh token. So refreshing JWT should be proceeded in Route Handlers. Create a route handler that issues new access token and sets it to response cookies. In Middleware, redirect to the refresh route if the access token has expired. Pseudo code: // middleware.ts
export async function middleware(req: NextRequest) {
if (accessTokenHasExpired()) {
return NextResponse.redirect(new URL(`/auth/refresh?redirectUrl=${req.url}`, req.url));
}
} // auth/refresh/route.ts
export async function GET(req: NextRequest) {
const redirectUrl = new URL(req.url).searchParams.get("redirectUrl");
const refreshToken = req.cookies.get("accessToken")?.value;
if (!validateRefreshTokenWithDB(refreshToken)) {
return NextResponse.redirect(new URL("/auth", req.url));
}
const accessToken = signAccessToken(refreshToken);
const response = NextResponse.redirect(url);
response.cookies.set("accessToken", accessToken, { ... });
return response;
} |
Beta Was this translation helpful? Give feedback.
This comment was marked as spam.
This comment was marked as spam.
-
The issue here is that we have absolutely no way of refreshing a user's session during SSR... We can validate it, refresh it in our DB, but at the end of the day we can't set the refreshed cookie directly. So instead of doing everything at once when you render the page, you have to:
This is not optimal and could easily be avoided if only we had the ability to set cookies during in RSC just like we can redirect. |
Beta Was this translation helpful? Give feedback.
-
I use a custom https://nextjs.org/docs/pages/building-your-application/configuring/custom-server // setting the cookie on the request. This will make cookies().get('newCookie') return the cookieValue
res.req.headers.cookie += `; newCookie=${cookieValue}`;
// This will set the cookie on the client for future request
res.setHeader('Set-Cookie', `newCookie=${newCookie}`); Hopes this helps someone. |
Beta Was this translation helpful? Give feedback.
-
This situation with Vercel and Next.js is simply unfortunate. Although Next.js is a widely used framework, it lacks a basic method for setting cookies on server components. This absolute neglect forces developers to resort to complicated workarounds and also imposes the overhead of using middleware just to set an updated cookie. The failure to address this fundamental issue and give it importance highlights a disconnect between developer needs and corporate priorities. It's absurd that such a glaring deficiency has persisted for so long in a framework that countless developers rely on. |
Beta Was this translation helpful? Give feedback.
-
I made a library to set cookies within the middleware to refresh tokens if they are out of date. This way it is possible to use updated tokens within a Server Component, for example. |
Beta Was this translation helpful? Give feedback.
-
@leerob Hey sir, is there any explanation to why this was closed as resolved ? Unless this is something that cannot be implemented, I wouldn't want to be forced to use middleware or some trick with client components as mentioned above to be able to renew the cookies and instead would hope to be able to set a new cookie if response status is 401 from some server side fetch wrapper or even delete a cookie if some criteria was met. |
Beta Was this translation helpful? Give feedback.
-
Is it possible to set a cookie from a RSC via a Route Handler ? // this function is called at the top of multiple RSC in my app
export async function handleGetCart() {
// some logic ...
if (cart.tokenValue) {
const res = await fetch(`${process.env.NEXT_PUBLIC_WEBSITE_URL}/api/cart-token`, {
method: "POST",
body: JSON.stringify({ cartToken: cart.tokenValue }),
})
console.log(res.headers)
console.log(cookies().getAll())
}
// some more logic ..
} // /api/cart-token/route.ts
export async function POST(request: NextRequest) {
const req = await request.json()
const cartToken = req.cartToken
cookies().set("cartToken", cartToken)
return new Response("test", {
status: 200,
// headers: {
// "Set-Cookie": `cartToken=${cartToken}`,
// },
})
} I've tried with the The problem is that I don't have the |
Beta Was this translation helpful? Give feedback.
-
One way to overcome this issue, and which I've found to be the most convenient method (validated on production environments), is to:
"use client";
import { useEffect, useRef } from "react";
interface Props {
someServerAction: () => Promise<void>;
}
export function SetHttpOnlyCookies(props: Props) {
const { someServerAction } = props;
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
ref.current?.click();
}, []);
return (
<input
type="hidden"
value={locale}
ref={ref}
onClick={someServerAction}
/>
);
} On some server component, just import and render the component: const serverAction = async () => {
// Set cookies; do whatever
}
<SetHttpOnlyCookies someServerAction={serverAction} /> |
Beta Was this translation helpful? Give feedback.
-
I like the idea of a |
Beta Was this translation helpful? Give feedback.
-
This and the middleware issue make pages router attractive again |
Beta Was this translation helpful? Give feedback.
-
Hey guys, so my problem is that I have a method which calls an api from server and this api sets some cookie how i can forward this cookie to browser I believe this feature should be there in any framework claiming to be capable for ssr. but as in next js we can set cookie from #1 server action which means i need to trigger my method from client and #2 I need to make a route handler which means i need to call this also from client side. where is ssr in this method. if there is any other please let me know @leerob. |
Beta Was this translation helpful? Give feedback.
-
any update about this problem? |
Beta Was this translation helpful? Give feedback.
-
Goals
Non-Goals
Background
When using an authentication service - such as Supabase, NextAuth or Auth0 - it is likely that a session would need to be refreshed before making a request for protected data from a Server Component. Since the
cookies
function fromnext/headers
only provides read access to cookies in Server Components, those routes need to be wrapped by a middleware.ts function, whose only purpose is to set the cookie for a refreshed session.With the introduction of writable cookies in Server Actions and Route Handlers, middleware is no longer required, simplifying the DX of working with cookies.
If Server Components were able to call the
set
method on thecookies
function, then cookies could be handled in exactly the same way across Server Actions, Server Components and Route Handlers. This means middleware could be used to solely implement middleware, rather than enabling write access for cookies on routes that happen to be Server Components, rather than Server Actions or Route Handlers, the understanding of which, requires a deep knowledge of Next.js and the App Router.From the standpoint of services trying to build libraries to make auth more seamless with Next.js, this would mean we could treat all the new server-side bits in the App Router the same, improving the overall DX of implementing auth.
Proposal
Allow Server Components to call the
set
method on thecookies
function fromnext/headers
Beta Was this translation helpful? Give feedback.
All reactions