Next.js Discord

Discord Forum

"Cookies can only be modified in a Server Action or Route Handler" error

Unanswered
Dutch posted this in #help-forum
Open in Discord
DutchOP
Hi guys . I'm new in nextjs and i created a rootlayout like below

export default async function RootLayout({ children }: Props) {
  const locale = await getLocale();
  const messages = await getMessages();
  const user = await verify();

  return (
    <html className="h-full overflow-hidden" lang={locale}>
      <body className="h-full overflow-hidden">
        <AppRouterCacheProvider>
          <NextIntlClientProvider messages={messages}>
            <StoreProvider initialUser={user}>
              <ToastProvider>{children}</ToastProvider>
            </StoreProvider>
          </NextIntlClientProvider>
        </AppRouterCacheProvider>
      </body>
    </html>
  );
}


verify.ts
'use server';
import { getMe } from '@/lib/services/auth.service';
import { cookies } from 'next/headers';

export async function verify() {
  let user: User | undefined;
  const cookieManager = await cookies();
  try {
    const token = cookieManager.get('token');
    if (token) {
      user = await getMe();
      if (!user) {
        cookieManager.delete('token');
      }
    }
  } catch {
    cookieManager.delete('token');
  }
  return user;
}


it gives error on catch block "cookieManager.delete('token');"
what is the problem ?

10 Replies

@Dutch Hi guys . I'm new in nextjs and i created a rootlayout like below ts export default async function RootLayout({ children }: Props) { const locale = await getLocale(); const messages = await getMessages(); const user = await verify(); return ( <html className="h-full overflow-hidden" lang={locale}> <body className="h-full overflow-hidden"> <AppRouterCacheProvider> <NextIntlClientProvider messages={messages}> <StoreProvider initialUser={user}> <ToastProvider>{children}</ToastProvider> </StoreProvider> </NextIntlClientProvider> </AppRouterCacheProvider> </body> </html> ); } verify.ts ts 'use server'; import { getMe } from '@/lib/services/auth.service'; import { cookies } from 'next/headers'; export async function verify() { let user: User | undefined; const cookieManager = await cookies(); try { const token = cookieManager.get('token'); if (token) { user = await getMe(); if (!user) { cookieManager.delete('token'); } } } catch { cookieManager.delete('token'); } return user; } it gives error on catch block "cookieManager.delete('token');" what is the problem ?
When using a server action onthe server (like you doing here), it will be automatically translated to a normal function to avoid performance issues.

And that means, that you call for example cookieManager.delete('token'); inside your server side page. And that is not allowed. It's only allowed inside a server action or route handler.

Iirc you can check auth in middleware and correctly remove/set cookies. Never check auth only inside your layout. Your page details may leak
DutchOP
i understand you but is it a good way to check auth in the middleware on every request ? i just store a token to cookie . i if client refresh the page, i get the cookie and check with it user has exists or not . we need a checking in middleware just do that ?
@Dutch i understand you but is it a good way to check auth in the middleware on every request ? i just store a token to cookie . i if client refresh the page, i get the cookie and check with it user has exists or not . we need a checking in middleware just do that ?
i understand you but is it a good way to check auth in the middleware on every request ?

its fine as long as you dont do fetching in middleware.ts/proxy.ts.

some people use middleware.ts/proxy.ts as "front-line" defense auth guard.

usually i just ignore the cookie if its invalid and return null and avoid using middleware.ts/proxy.ts at all.
extra: you dont need to worry about wasting resource of getMe() or doing unecessary fetch of getMe() since you can just data-cache the data and it will be instantly returned
@Dutch i understand you but is it a good way to check auth in the middleware on every request ? i just store a token to cookie . i if client refresh the page, i get the cookie and check with it user has exists or not . we need a checking in middleware just do that ?
What alfon says and: use middleware as long as there are no fetches. So just checking if the cookie valid by checking its JWT is completely fine. Like that you can redirect instantly to „/auth“ page if the user is not authenticated

I normally check the auth in the middleware (to route correctly), check on the page as well (to get user data) and if there are any route handlers/server actions, that the client can use, I check inside them too. To secure your app, you might want to do the same
Pacific sand lance
the issue is that you can't modify headers/cookies/anything related to request/response in RSCs
even if you call server action from RSC it's still called from within RSC
@Dutch how should i get the user info if client refresh the on anywhere ? forexample, client is in the dashboard page and refresh the page, how can i get the user info and store it to the redux ? then, user must continue with the same page ( where should i call getMe method ? )
I normally check the auth in the middleware (to route correctly), check on the page as well (to get user data) and if there are any route handlers/server actions, that the client can use, I check inside them too. To secure your app, you might want to do the same