Unable to update cookies in Server Components after refreshing expired access tokens

Description:
When handling authentication in a Next.js App Router setup, we face a limitation where cookies cannot be updated from Server Components, making it difficult to refresh and persist new access tokens during SSR (Server-Side Rendering).
Problem Scenario

  1. User loads a page at 10:00:00.
  2. Middleware runs at 10:00:00:
    • Token expires at 10:00:30.
    • Token is valid (30 seconds left).
    • Middleware allows the request.
  3. Server Component begins rendering at 10:00:05.
  4. Inside the Server Component, an API call is made at 10:00:35.
    • The token has now expired.
    • API returns 401 Unauthorized.
    :cross_mark: There’s no way to update cookies with the refreshed token.

Expected Behavior
If a token expires during a server-rendered request, there should be a mechanism for the Server Component (or the code running within it) to update cookies — for example, after calling a refresh token API.
Actual Behavior
In Server Components:
• We can read cookies using cookies() from next/headers .
• We cannot set or update cookies.
• Even if we trigger a Server Action or Route Handler from a Server Component, it cannot update cookies in the same request lifecycle.

Example Code

import { cookies } from ‘next/headers’;
export default async function Page() {
const cookieStore = await cookies();
// ❌ Cannot set cookie directly.
cookieStore.set(‘theme’, ‘dark’); // Throws error.
// ❌ Cannot update cookie via server action.
await updateCookieAction();
// ❌ Cannot update cookie via route handler call either.
await fetch(‘/api/update-cookie’, { method: ‘POST’ });
return ‘…’;
}

const JobPostings = async () => {
const response = await getAllJobPostings();
if (response.status_code === 401) {
// Refresh token successfully
const newAccessToken = await refreshAccessToken();
// ❌ Cannot update cookie from Server Component.
updateCookies(newAccessToken);
}
return (…);
};

Why This Is a Problem
Middleware can refresh tokens only on navigation requests — not for API calls made from Server Components during SSR.
This creates a gap where a page can fail to render because the server cannot persist the new token, even though it has successfully refreshed it in memory.
Questions / Suggestions
• Could there be a secure API or Response helper added to allow cookie updates from within a Server Component context?
• Alternatively, can Next.js provide a built-in authentication lifecycle hook that bridges Middleware and Server Components (e.g., to retry and persist refreshed tokens in cookies within the same request)?

Hi @devpreet0137-2917, welcome to the Vercel Community!

As per the docs,

cookies is an async function that allows you to read the HTTP incoming request cookies in Server Components, and read/write outgoing request cookies in Server Actions or Route Handlers.

I think you can make a Server Action to handle this scenario. Like following:

// actions/auth.ts
'use server'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'

export async function refreshTokenAction() {
  try {
    const newToken = await refreshAccessToken()
    const cookieStore = await cookies()
    cookieStore.set('access_token', newToken, {
      httpOnly: true,
      secure: true,
      sameSite: 'strict'
    })
    // Redirect to refresh the page with new token
    redirect('/current-page')
  } catch (error) {
    redirect('/login')
  }
}

but if the access token is expired while executing the api in server component then we don’t be able to save the cookies either we use the server action or route handler to update the cookies. Please look into the below snapshot or (am i implementing in wrong way )