Cookies() doesn't want to run on a Server Action
Answered
Horned Puffin posted this in #help-forum
Horned PuffinOP
I have a Server Action that I created in NextJS 14 TypeScript App Router.
The issue is that when I hit the cookies().set() line, I get this error:
Error th [Error]: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
The doc clearly says that cookies() work specifically on Server Actions (such as the one I defined) and that Server Actions are defined with the 'use server' key word.
What is causing this issue?
import { cookies } from 'next/headers'
export const getTokens = async (code: string): Promise<string> => {
'use server'
console.log('\n entering SERVER ACTION: getTokens(code) . . .\n');
const envIntegrationKey = process.env.NEXT_PUBLIC_DOCUSIGN_INTEGRATION_KEY
const envSecretKey = process.env.DOCUSIGN_SECRET_KEY
const tokenURI = 'https://account-d.docusign.com/oauth/token/';
const credentials = btoa(${envIntegrationKey}:${envSecretKey});
const reqBody = new URLSearchParams();
reqBody.append('grant_type', 'authorization_code');
reqBody.append('code', code);
const response = await fetch(tokenURI, {
method: 'POST',
headers:{
Authorization:Basic ${credentials}},
body: reqBody
})
if (response.ok) {
console.log('response OK: ', response.status, 'Status Text: ', response.statusText);
const data = await response.json()
const accessToken: string = data.access_token;
const refreshToken: string = data.refresh_token;
const expiresIn: string = data.expires_in.toString();
cookies().set('accessToken', accessToken)
cookies().set('refreshToken', refreshToken)
//rest of codeThe issue is that when I hit the cookies().set() line, I get this error:
Error th [Error]: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
The doc clearly says that cookies() work specifically on Server Actions (such as the one I defined) and that Server Actions are defined with the 'use server' key word.
What is causing this issue?
10 Replies
cookies() work with server action but look like you are not using server action correctly@Horned Puffin I have a Server Action that I created in NextJS 14 TypeScript App Router.
`
import { cookies } from 'next/headers'
export const getTokens = async (code: string): Promise<string> => {
'use server'
console.log('\n entering SERVER ACTION: getTokens(code) . . .\n');
const envIntegrationKey = process.env.NEXT_PUBLIC_DOCUSIGN_INTEGRATION_KEY
const envSecretKey = process.env.DOCUSIGN_SECRET_KEY
const tokenURI = 'https://account-d.docusign.com/oauth/token/';
const credentials = btoa(`${envIntegrationKey}:${envSecretKey}`);
const reqBody = new URLSearchParams();
reqBody.append('grant_type', 'authorization_code');
reqBody.append('code', code);
const response = await fetch(tokenURI, {
method: 'POST',
headers:{
Authorization: `Basic ${credentials}`
},
body: reqBody
})
if (response.ok) {
console.log('response OK: ', response.status, 'Status Text: ', response.statusText);
const data = await response.json()
const accessToken: string = data.access_token;
const refreshToken: string = data.refresh_token;
const expiresIn: string = data.expires_in.toString();
cookies().set('accessToken', accessToken)
cookies().set('refreshToken', refreshToken)
//rest of code`
The issue is that when I hit the cookies().set() line, I get this error:
Error th [Error]: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
The doc clearly says that cookies() work specifically on Server Actions (such as the one I defined) and that Server Actions are defined with the 'use server' key word.
What is causing this issue?
Silver Marten
i think you're trying to import the server action in a client component, try putting
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#client-components
"use server" at the top of your filehttps://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#client-components
To call a Server Action in a Client Component, create a new file and add the "use server" directive at the top of it. All functions within the file will be marked as Server Actions that can be reused in both Client and Server Components:Horned PuffinOP
Tried it that way - still no luck :/
@Horned Puffin Tried it that way - still no luck :/
what did you try? could you show the code on where you call
getTokens()?Horned PuffinOP
Here is the page.tsx component calling the getTokens(). User clicks button, leads to DocuSign Login page, login access provides code that is exchanged for AccessToken
import {getTokens} from '@/app/lib/docusign';
import Link from 'next/link';
export default async function Page(props: any) {
//Step 1 - User Login to DocuSign for Access
const integrationKey = process.env.NEXT_PUBLIC_DOCUSIGN_INTEGRATION_KEY;
const redirectUri = 'http://localhost:3000/dashboard/forms';
const scope = 'signature';
const docuLoginURI =d.com/oauth/auth?response_type=code&scope=${scope}&client_id=${integrationKey}&redirect_uri=${redirectUri};
let authCode;
if (props.searchParams.code) {
console.log('code parameter exists - enter client-side POST handler')
console.log('code: ', props.searchParams.code);
authCode = props.searchParams.code;
console.log('authCode Assignment Check Inside IF: ', authCode);
}
console.log('authCode Assignment Check Outside IF: ', authCode);
//Step 2 - Store Code, send to Server Actions
if (authCode) {
console.log('code parameter exists - enter client-side POST handler')
const handleTokenPost = async () => {
console.log('Entering handleTokenPost function')
try {
const tokenMessage = await getTokens(authCode);
console.log('handleTokenPost() in Page.tsx - tokenMessage: ', tokenMessage);
} catch (error) {
console.error('Error', error)
}
}
handleTokenPost()
}
return (
<main className="h-screen w-full">
<Link
type="button"
className="flex h-10 items-center rounded-lg w-24 border border-solid border-black bg-yellow-200 px-4 text-sm font-medium"
href={docuLoginURI}
>
DocuSign
</Link>
</main>
);
}@Ray https://nextjs-faq.com/server-action-call-inside-server-component-rendering
have you read this link? you are not using server action
Horned PuffinOP
I should have opened that up right away -- many thanks for the gentle reminder. I truly appreciate you taking the time to help me sort this out!
@Horned Puffin I should have opened that up right away -- many thanks for the gentle reminder. I truly appreciate you taking the time to help me sort this out!
np, I think you should create a route handler for that
@Ray np, I think you should create a route handler for that
Horned PuffinOP
It's wild you say that, that's exactly what I did after racking my brain for hours lol . Route handlers worked perfectly. I was still really hoping to figure this out and you've satisfied a huge curiosity by finding that link
I'll have to check out the nextjs-faq from now on, didn't know about it at all
I'll have to check out the nextjs-faq from now on, didn't know about it at all