Can I parse the Payload cookie from another API?

default discord avatar
notchrlast year
14

Good morning! I have another API where I want to verify the user is a Payload user / has a session. Am I able to accomplish this using the request credentials of a signed in user?



So basically I'd send a request with credentials: true to my other API (non-payload)



I can see that a non-signed cookie is on the request



{
  'payload-token': 'secret-token'
}


Can I then use my payload secret on the non-payload API to verify that is a valid user?



OK so I've opted to go with JWT



And I have the JWT on my other API and my payload secret



I setup a function to check the token before my API responds to requests



const verifyToken = (req: express.Request, res: express.Response): boolean => {
  if (req.cookies["payload-token"]) {
    console.log(req.cookies["payload-token"], process.env.PAYLOAD_SECRET);
    try {
      const decoded = jwt.verify(
        req.cookies["payload-token"],
        process.env.PAYLOAD_SECRET,
        {
          algorithms: ["HS256"],
        }
      );
      console.log(decoded);
      return true;
    } catch (err) {
      console.log("Invalid token request.", err);
      return false;
    }
  } else {
    console.log("Missing token in request.");
    return false;
  }
};


However, I keep getting

Invalid token request. JsonWebTokenError: invalid signature


@jmikrut Sorry for the ping, any idea on why the signature may have failed? I confirmed that both are passed to the verifyToken function and the secret is from my Payload env



What's even odder, is that the signature is valid when testing the combo on

https://jwt.io/


There will be another condition in the fn btw checking the result of decoded



But rn it throws each time



Things I have tried so far:



1.) Tried to base64 encode the payload secret.
2.) Tried to specify the correct algorithm


However, the result from jwt.io still says the signature is valid while jsonwebtoken reports the opposite



@jmikrut WOW 3 pings, i am so sorry, this is what I am stuck on

  • discord user avatar
    jmikrut
    last year

    I can help here in a bit - wrapping up my meetings shortly

  • default discord avatar
    notchrlast year

    Ah thank you so much!



    I think that the payload secret is NOT the signing key for the JWT

  • discord user avatar
    jmikrut
    last year

    ok i am alive



    so, i bet what your issue is, is that you need to hash your raw

    secret

    in the same way that Payload does internally:



    https://github.com/payloadcms/payload/blob/master/src/payload.ts#L164


    notice how we are taking whatever you provide as a secret string, hashing it, and then taking only the first 32 chars



    then from there you should be able to verify the token in the same way that we do in our auth operations, for example, here:



    https://github.com/payloadcms/payload/blob/master/src/auth/operations/refresh.ts#L60
  • default discord avatar
    notchrlast year

    Hey, following up, this worked perfectly!

  • discord user avatar
    jmikrut
    last year

    amazing

  • default discord avatar
    notchrlast year

    @jmikrut One thing I should mention



    The decoded JWT is an object with that you would expect (including the saveToJWT data)





    But it seems to want a string or jwtpayload?



    Do I need to make an interface for what I expect back?



    Maybe I should be running jqt.verify, then jwt.decode, but it feels like an extra step / may not resolve the type issue

    image.png
  • discord user avatar
    jmikrut
    last year
    jwt.verify

    returns the results of what you would send back with

    decode

    i believe

  • default discord avatar
    notchrlast year

    Anyway, not the hugest deal, but wanted to mention it

  • discord user avatar
    jmikrut
    last year

    it just adds an extra step to verify the token

  • default discord avatar
    notchrlast year

    Hmmm the value I get back from the .verify is the object, maybe I'm doing something wrong



          const decoded = jwt.verify(req.cookies["payload-token"], hash, {
            algorithms: ["HS256"],
          });


    logging decoded =



    {
      email: 'cmcgrane@saa.com',     
      id: '63b84be941b40f6bd0a5899b',
      collection: 'users',
      repid: '229784',
      iat: 1679420667,
      exp: 1679427867
    }
  • discord user avatar
    jmikrut
    last year

    that looks like what i would expect

  • default discord avatar
    notchrlast year

    hmm



    It expects decoded to be

    string | JwtPayload


    oh maybe JwtPayload is the object, it just wouldn't know of any props on it



    In any case, not sure if this is good practice but



    interface jwtResponse {
      email: string,     
      id: string,
      collection: string,
      repid: string,
      iat: number,
      exp: number
    }


          const decoded = jwt.verify(req.cookies["payload-token"], hash, {
            algorithms: ["HS256"],
          });
          const {repid} = (decoded as jwtResponse)


    😅



    I feel bad because I never post easy questions

  • discord user avatar
    jmikrut
    last year

    i'd just say

    if (typeof decoded !== 'string')


    i'm not sure why that library could send back a string, maybe in the case of an error - - or maybe the contents of the token in the first place could be a string, in which point, by verifying, it would send

    back

    a string



    generally you should avoid using

    as

    and instead verify / narrow types manually

  • default discord avatar
    notchrlast year

    Thank you, will do!!

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

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