Next.js Discord

Discord Forum

Can't assign cookies in server action

Answered
caleb posted this in #help-forum
Open in Discord
Hey y'all!

Working on adding magic links to my site for authentication. I got the email and authentication token portion setup and functioning, but am having difficulty setting cookies.

Below is my code for /auth/signin/[token]/page.tsx, using the App Directory. Once I verify the token provided in the URL is valid in my database and not expired via tRPC, I get to signing a JWT and setting it in the client's cookies.
Answered by joulev
* do this in a route handler.
* page.tsx files are not server actions and should not have "use server".
View full answer

7 Replies

'use server'

import { redirect } from 'next/navigation'
import { api } from '~/trpc/server'
import chalk from 'chalk'
import * as jose from 'jose'
import { env } from '~/env'
import { cookies } from 'next/headers'

export default async function Verify({ params: { token } }: { params: { token: string } }) {
    const { message } = await api.authenticationToken.verifyUserAuthenticationTokenCode({ token })

    if (message === 'not_found') {
        return redirect('/signin?message=code_not_found')
    }

    if (message === 'expired') {
        return redirect('/signin?message=code_expired')
    }

    if (message === 'verified') {
        const secret = new TextEncoder().encode(env.JWT_SECRET)
        const alg = 'HS256'
        const user = await api.user.getUserByAuthToken({ token })

        const jwt = await new jose.SignJWT().setProtectedHeader({ alg }).setIssuedAt().setIssuer('urn:collegefront:issuer').setAudience('urn:collegefront:audience').setSubject(String(user?.id)).setExpirationTime('72h').sign(secret)

        try {
            cookies().set('Authorization', jwt, {
                secure: true,
                httpOnly: true,
                expires: new Date(Date.now() + 72 * 60 * 60 * 1000),
                path: '/',
                sameSite: 'strict'
            })

            return redirect('/profile')
        } catch (error) {
            console.error(chalk.redBright(chalk.bold('\nError setting cookie:')), String(error) + '\n')
            return redirect('/signin?message=unknown_error')
        }
    }

    console.log(chalk.yellowBright(chalk.bold('Strange error:')), message)

    return redirect('/signin?message=unknown_error')
}


However, once I get to this point I get the error in the image attached from my try-catch console log. As you can see, I'm clearly setting this route as a Server Action with 'use server' at the top.

What am I missing? Forigve me for any client/server component mistakes, I'm still figuring them out.
Answer
As you can see, I'm clearly setting this route as a Server Action with 'use server' at the top.
@caleb route handlers are different from server actions, you don't need "use server"
Below is my code for /auth/signin/[token]/page.tsx
Also you are saying this is your page which is a server component by default in app router - you again don't need "use server"
I think you can simply remove "use server" first
also redirect() internally throws an error so try catch won't work as expected with redirect()
Ahh that's it. I still need to figure out server actions lol. Thanks for the help!