Expired token response after successful login

default discord avatar
aamdmn
3 months ago
19

Hi. I'm experimenting with the new Next.js server actions trying to use it for auth purposes. I'm making a simple fetch request to my

Users

endpoint to login to the application. The problem I'm facing is it doesn't set the cookie automatically after successful login. I tried to create it manually using

next/cookies

and pass the token as a value but it seems the token in expired and can't be used for authorization.


"use server"

    const password = data.get("password")
    const email = data.get("email")

    const res = await fetch(`${process.env.PAYLOAD_CMS_URL}/api/users/login`, {
      method: "POST",
      credentials: "include",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        email,
        password
      }),
    })

    const resData = await res.json()

    cookies().set({
        name: "payload-token",
        value: resData.token,
        // expires: new Date(`${resData.exp * 1000}`),
        path: "/",
        httpOnly: true,
        secure: true,
        sameSite: "lax"
      })

I also have added right

csrf

domains in payload config. But it doesn't seem to work.

  • default discord avatar
    notchr
    3 months ago

    @aamdmn Morning!



    You've added both the cors / csrf allowed urls?



    I see you've added credentials: "include", that's good



    Do you get any messages in your dev console?

  • default discord avatar
    aamdmn
    3 months ago

    @notchr Hi thank you for your respond. Yes both cors and csrf should be added correctly.



    You mean in the payload console or next dev console? 😄

  • default discord avatar
    notchr
    3 months ago

    You shouldn't need to manually set a cookie



    Ah sorry, browser console



    Let's check out the request it makes on logic



    login*



    And inspect the set cookies in your developer tools



    (if any)

  • default discord avatar
    aamdmn
    3 months ago

    There is no set cookie header unfortunately.



    I'm using server actions. Maybe that's the problem



    But the returned token should be correct right?

  • default discord avatar
    notchr
    3 months ago

    Well



    You can paste the token into jwt.io



    And check that it has the correct info



    I recall a similar issue to this posted recently, I can search threads in a tiny bit



    But basically, the fetch request should be auto setting a cookie that includes the token



    That is, if you've logged in via the /login endpoint



    It depends on how you're expecting the auth to happen



    your request looks correct

  • default discord avatar
    aamdmn
    3 months ago

    i checked the token and it's correct but it seems I can't use it. It always returns a

    You are not allowed to perform this action

    .

    image.png
  • default discord avatar
    notchr
    3 months ago

    Can you share the access control on the admin collection

  • default discord avatar
    aamdmn
    3 months ago

    what's even weirder is if I log in to the cms, the cookie updates automaticaly in my FE.

  • default discord avatar
    notchr
    3 months ago

    On your user/admin collection, lets check the access control



    Also out of curiosity, what do you mean that the token says "you are not allowed to perform this action"



    like when you do subsequent requests?

  • default discord avatar
    aamdmn
    3 months ago

    Yeah, the access control is pretty straightforward. I have two collections Users and Orders. Each user has it's role(admin, cleaner, customer). Admins and cleaners can see all orders and customers can only see orders assigned to them.



    This is orders access control:


    access: {
            read: isAdminOrHasOrderAccess('id'),
            create: isAdmin,
        },

    import { Access } from "payload/config"
    
    export const isAdminOrHasOrderAccess = (orderIDFieldName: string = 'order'): Access => ({ req: { user } }) => {
        if (user) {
            if (user.role === 'admin' || user.role === 'cleaner') {
                return true
            }
    
            if (user.role === 'customer' && user.orders?.length > 0) {
                return {
                    or: [
                        {
                            [orderIDFieldName]: {
                                in: user.orders
                            }
                        },
                        {
                            [orderIDFieldName]: {
                                exists: false
                            }
                        }
                    ]
                }
            }
        }
    
        return false
    }

    After successful login every user should see their orders.



    it says in further requests using the returned token in authorization header.

  • default discord avatar
    notchr
    3 months ago

    Well



    By default the cookies should manage the auth state



    I'm wondering, since your access logic is a little complex



    If you comment out that access and set it to true so that its unrestricted



    do you still have issues?



    I would start there

  • default discord avatar
    aamdmn
    3 months ago

    yes, there are no issues. it show the orders normally.



    sorry for late respond

  • default discord avatar
    notchr
    3 months ago

    Ah okay, well then we know the source of the issue! Were you able to resolve?

  • discord user avatar
    jarrod_not_jared
    Payload Team
    3 months ago

    I am wondering how this will work since you are trying to auth server to server. How do you know the domain that makes the request to whitelist?



    I feel like you would need to use payloads local api to login 🤔

  • default discord avatar
    notchr
    3 months ago

    Another way is to parse a jwt on a server, so that you can verify it came from a specific source

  • default discord avatar
    aamdmn
    3 months ago

    I think, there are no problems with the access control, the problem is with the cookie on the FE. You see, if I log in on the FE and set the cookie manually (because it won't set up automatically) it won't let me thru

    You are not allowed...

    . Then if I log in to the CMS, it updates or changes my cookie on the FE with the right expire date, right token and all that stuff and if I refresh it show the orders as expected. I don't understand why 😄 And also, why is the token returned from the

    users/login

    invalid?



    Do you have any examples how can I implement the local API to my Next app? I'm using the new

    app

    router. Do I need to have monorepo to be able to use the local api?



    I think I have similar problem to this thread:

    https://discord.com/channels/967097582721572934/1123857321030856714
  • default discord avatar
    notchr
    3 months ago

    @aamdmn How do you know it's invalid?



    Did you verify it with a jwt parser?

  • default discord avatar
    aamdmn
    3 months ago

    When I'm trying to refresh it with

    /refresh-token

    it says

    jwt expired


    yes



    Okay, I was able to fix it. It was pretty simple actually. I just switched the hole login process to the client. It now sets the cookie like it should. Thank you @notchr @jarrod_not_jared for the time and help!

  • default discord avatar
    notchr
    2 months ago

    Nicely done!

Open the post
Continue the discussion in Discord
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.