Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Cookie is not set in production but works in local

default discord avatar
generator101last year
62

I am setting up basic authentication using the example repo and the cookie is set in frontend when on local host but when I deployed it to render.com, it no longer sets the cookie.


auth: {
    tokenExpiration: 28800, // 8 hours
    cookies: {
      sameSite: 'none',
      secure: true,
      domain: process.env.COOKIE_DOMAIN,
        },
    },

in my .env for local, cookie domain is set to

COOKIE_DOMAIN=localhost

and in production, I changed it to

.onrender.com

but still not able to store the cookie.

  • default discord avatar
    notchrlast year
    @944284724824801302

    Hmm, I didn't have to pass the domain in, interesting



    Did you set CORS/CSRF settings too?



    Also, may not be necessary but, in my server.ts, I manually specify the cors config and also pass credentials: true



    app.use(
      cors({
        origin: [
          "http://localhost:4200",
          "https://www.example.com",
        ],
        credentials: true,
      })
    );


    Are you using credentials: 'include' in your request on the frontend?

  • default discord avatar
    generator101last year

    in the config files, I have this



    cors: [
            process.env.PAYLOAD_PUBLIC_SERVER_URL || '',
            process.env.PAYLOAD_PUBLIC_SITE_URL || '',
        ].filter(Boolean),
        csrf: [
            process.env.PAYLOAD_PUBLIC_SERVER_URL || '',
            process.env.PAYLOAD_PUBLIC_SITE_URL || '',
        ].filter(Boolean),


    In frontend, I used this



    import { cookies } from 'next/headers'
    
    const me = await fetch(
      process.env.PAYLOAD_PUBLIC_SERVER_URL + '/api/users/me',
      { headers: { Cookie: cookies().toString() } }
    ).then((r) => r.json())


    method: 'POST',
        credentials: 'include',
        headers: {
        'Content-Type': 'application/json',
         .....
    },


    Any help with this will be greatly appreciated 😅



    @967118574445547650

    any help with this? thanks



    cant figure out why cookie is not working in production

  • default discord avatar
    notchrlast year
    @944284724824801302

    is this based off a payload next template repo?

  • discord user avatar
    denolfe
    last year

    I'm not the best to answer here. Maybe

    @281120856527077378

    or

    @808734492645785600

    can weigh in.

  • I am guessing that PAYLOAD_PUBLIC_SERVER_URL is not defined in prod. Check out this GH discussion, let me know if it clears things up for you!



    https://github.com/payloadcms/payload/issues/1654#issuecomment-1403972303
  • discord user avatar
    jacobsfletch
    last year
    @944284724824801302

    also check that the prefixed period in your cookie domain isn’t the problem. I would expect this value to be

    onrender.com

    and not

    .onrender.com

    .

  • default discord avatar
    generator101last year
    @281120856527077378

    I tried adding

        serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || 'http://localhost:8000',

    but still did not work,



    @808734492645785600

    that didnt help too, it still does not set the cookie. Have you guys tested that nextjs auth in production environment? thanks

  • discord user avatar
    jacobsfletch
    last year
    @944284724824801302

    I think what

    @281120856527077378

    is suggesting is to ensure your variables are not undefined in production for some reason like incorrect dotenv config, etc

  • Yeah I would console log one of em above your payload config file in your prod environment and see what they log. Undefined or the env var?

  • default discord avatar
    generator101last year
    @281120856527077378

    I just did

    payload.logger.info(`Public Server URL: ${process.env.PAYLOAD_PUBLIC_SERVER_URL}`)

    and it loaded the url I added in env variables



    Jul 12 06:30:48 PM [22:30:48] INFO (payload): Starting Payload...


    Jul 12 06:30:52 PM [22:30:52] INFO (payload): Admin URL: localhost:8000/admin


    Jul 12 06:30:52 PM [22:30:52] INFO (payload): Public Server URL: MY URL FROM ENV


    Jul 12 06:30:54 PM Your service is live 🎉





    this is what I see in the console log of the server

  • discord user avatar
    jacobsfletch
    last year

    Open you browser’s Application tab in the inspector console and take a look at the cookie that was set.



    From there you can inspect the domain property being used, etc

  • default discord avatar
    generator101last year

    I cant even login to backend





    my user collection



    import type { CollectionConfig } from 'payload/types'
    
    import { admins } from './access/admins'
    import adminsAndUser from './access/adminsAndUser'
    import { anyone } from './access/anyone'
    import { checkRole } from './access/checkRole'
    import { loginAfterCreate } from './hooks/loginAfterCreate'
    import { protectRoles } from './hooks/protectRoles'
    
    export const Users: CollectionConfig = {
        slug: 'users',
        auth: {
            tokenExpiration: 28800, // 8 hours
            cookies: {
                sameSite: 'none',
                secure: true,
                domain: process.env.COOKIE_DOMAIN,
            },
        },
        admin: {
            useAsTitle: 'email',
        },
        access: {
            read: adminsAndUser,
            create: anyone,
            update: adminsAndUser,
            delete: admins,
            // admin: ({ req: { user } }) => checkRole(['admin'], user),
        },
        hooks: {
            afterChange: [loginAfterCreate],
        },
        fields: [
            {
                name: 'firstName',
                type: 'text',
            },
            {
                name: 'lastName',
                type: 'text',
            },
            {
                name: 'username',
                type: 'text',
                required: true,
                unique: true,
                index: true,
            },
            {
                name: 'roles',
                type: 'select',
                hasMany: true,
                saveToJWT: true,
                hooks: {
                    // temp disable this hook
                    // beforeChange: [protectRoles],
                },
                options: [
                    {
                        label: 'Admin',
                        value: 'admin',
                    },
                    {
                        label: 'User',
                        value: 'user',
                    },
                ],
            },
        ],
    }
  • default discord avatar
    notchrlast year
    @944284724824801302

    This is likely an issue with your adminsAndUser function. Are you able to access if you set your access levels to true temporarily



    for instance



            read: () => true,
            create: anyone,
            update: adminsAndUser,
            delete: admins,


    Just to narrow down what is causing this

  • Also - what site are you trying to log into? Does the Cookie domain match?

  • default discord avatar
    generator101last year
    @281120856527077378

    I am trying to login to backend and I get unauthorized error, I try to login to frontend and it doesnt set cookie

  • are you logging into

    https://some-domain.com

    and your cookie domain is

    some-domain.com

    (I don't think cookie domain needs to be fully qualified)

  • default discord avatar
    generator101last year

    I deployed backend and frontend to render.com, the backend is

    ex-mybackend.onrender.com

    and frontend is

    ex-myfrontend.onrender.com
  • Right, but what is

    domain: process.env.COOKIE_DOMAIN,
  • default discord avatar
    generator101last year

    onrender.com





    I have been trying so many different things and still not working, initially frontend was deployed on vercel



    I moved it to render to have same domain

  • right right



    it has to be something simple, hmmm

  • default discord avatar
    generator101last year


    and this is the user in mongo db

  • right, I think this specifically has to do with cookies/csrf

  • default discord avatar
    generator101last year
    dotenv.config({
        path: path.resolve(__dirname, '../.env'),
    })
    
    export default buildConfig({
        serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || 'http://localhost:8000',
        collections: [Users],
        cors: [
            process.env.PAYLOAD_PUBLIC_SERVER_URL || '',
            process.env.PAYLOAD_PUBLIC_SITE_URL || '',
        ].filter(Boolean),
        csrf: [
            process.env.PAYLOAD_PUBLIC_SERVER_URL || '',
            process.env.PAYLOAD_PUBLIC_SITE_URL || '',
        ].filter(Boolean),
        typescript: {
            outputFile: path.resolve(__dirname, 'payload-types.ts'),
        },
    })


    my config file

  • with render do you get to pick your domain name? do you have that set at your PAYLOAD_PUBLIC_SERVER_URL & PAYLOAD_PUBLIC_SITE_URL envs

  • default discord avatar
    generator101last year


    I set the Public site URL to the frontend url



    and server URL to the backend url



    and I did

    payload.logger.info(`Public Server URL: ${process.env.PAYLOAD_PUBLIC_SERVER_URL}`)
  • and it logs correctly huh

  • default discord avatar
    generator101last year

    yeah



    😭

  • where did you do the log?



    in the payload config file? what about the server file? (built server file)

  • default discord avatar
    generator101last year
    @1049775120559898725

    changing

    read: () => true,

    still doesnt let me login



    @281120856527077378

    on the server



    const start = async (): Promise<void> => {
        await payload.init({
            secret: process.env.PAYLOAD_SECRET,
            mongoURL: process.env.MONGODB_URI,
            express: app,
            onInit: () => {
                payload.logger.info(`Admin URL: localhost:${process.env.PORT}/admin`)
                payload.logger.info(`Public Server URL: ${process.env.PAYLOAD_PUBLIC_SERVER_URL}`)
            },
        })
  • I would also add a log above your buildConfig function

  • default discord avatar
    notchrlast year

    I agree with Jarrod then, likely cors/csrf

  • in both your server file and your config file you are using the same:


    dotenv.config({
        path: path.resolve(__dirname, '../.env'),
    })


    So below that I would log

    process.env.PAYLOAD_PUBLIC_SERVER_URL

    (in each file)

  • default discord avatar
    generator101last year

    on server I have this



    dotenv.config()


    on config file I have this



    dotenv.config({
        path: path.resolve(__dirname, '../.env'),
    })
  • right, all relative to where the env is

  • default discord avatar
    generator101last year

    I think I added this one after reading your comment yesterday



    for linking that github issue

  • are your server and config file at the same level in the same dir?

  • default discord avatar
    generator101last year


    yes

  • NICE



    so just change your dotenv config in your payload config, thats the issue

  • default discord avatar
    generator101last year

    I did the log and it outputs the domain



    Jul 13 10:58:03 AM  > server@0.1.0 build:payload
    Jul 13 10:58:03 AM  > cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload build
    Jul 13 10:58:03 AM  
    Jul 13 10:58:05 AM  CONFIG LOG: domain.onrender.com
  • Ok, just for clarity, can you change the dotENV in the server file to match the one in your payload config file

  • default discord avatar
    generator101last year

    nope, that didnt help either



    I see a lot of these logs







    should I change the

    process.env.COOKIE_DOMAIN

    to

    .onrender.com

    ?

  • default discord avatar
    generator101last year

    damn, for real? omg



    maybe I can try payload cloud then



    it never occurred to me it can be related to render, I have another payload app with custom domain

  • you mean instead of using their auto generated ones?

  • default discord avatar
    generator101last year

    yeah, I setup a custom domain for my other app, maybe I can try setting a custom domain for this one too



    also setting up process.env.COOKIE_DOMAIN as full domain of the backend didnt help



    omg it logged in using custom domain



    https://tenor.com/view/facepalm-really-stressed-mad-angry-gif-16109475
  • got 2 luv it

  • default discord avatar
    generator101last year

    thank you for all your help, I hope I can migrate some side projects to payload cloud when free plan is here

  • Yeah no prob! glad we got to the bottom of it

  • default discord avatar
    generator101last year
    @281120856527077378

    thanks, yeah



    also if I uncomment ``beforeChange: [protectRoles],



    the user role is changed from admin to just user



    I remember discussing this with you



    oh looks like it is updated

    https://github.com/payloadcms/payload/blob/master/examples/auth/cms/src/collections/hooks/protectRoles.ts

    I still think there is a bug in that function, if a user is already admin, it will change it to user if just using

    const isAdmin = req.user?.roles.includes('admin')


    req.user?.roles returns undefined

  • default discord avatar
    generator101last year

    yes, are we sure req has users?



    I changed it to

    const isAdmin = data.roles.includes('admin')


    and seems to be working



    but I tried to log

    req.user

    and it gave me undefined

  • right, but that means I could pass formData saying I am an admin and I will become an admin. Whereas admins should only be able to add admins

  • default discord avatar
    generator101last year

    I see, yeah that should not happen but with current code, if I am an admin and I login, my role is changed to user



    because

    const isAdmin = req.user?.roles.includes('admin')

    always returns false



    since req.user is undefined

  • when you login, user will attach to the req. So something is amiss in your situation



    if you clone the repo and cd into that examples/auth/cms folder and run

    yarn && yarn dev

    what happens? Can you login?

  • default discord avatar
    generator101last year

    so this line that checks for email



      const isAdmin = req.user?.roles.includes('admin') || data.email === 'demo@payloadcms.com' // for the seed script


    works



    but the problem is that if I have bunch of admin users



    I can't check their emails



    if you remove

    data.email === 'demo@payloadcms.com'

    it will not work

  • The email check if only so the first user can be created as an admin. Once you have 1 admin you could remove that portion, and then just check the user roles on the req. But if you clone it down and do what I said above, you are saying that user.roles is undefined?

  • default discord avatar
    generator101last year

    yes



    I cloned the repo locally and added my db

  • what if you clone and use a blank db

  • default discord avatar
    generator101last year

    I did not try that yet

  • if you do make sure to make the first user with the demo@payloadcms.com email

  • default discord avatar
    generator101last year

    if you remove the data.email === ... part you are able to login?

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.