Mila A
Mila A

Reputation: 569

JWT Invalid signature from one website, but no errors with another. Extra properties of user object get added to token

Problem

I have two websites. One is production, but a very very old version. Another is just localhost where I'm currently testing it. After involving NextAuthJS to the NextJS website, I need to integrate my NextAuthJS session provider to the remote ExpressJS backend.

  1. I make a request to /login ->

    1. on remote backend I generate a JWT token, and get full user details.
    2. then I send data to the NextJS website.
    3. using NextAuthJS, store it in a cookie.

  1. In case I need to get any user specific details, such as saved videos:

    1. I make a request from NextJS website.
    2. On remote ExpressJS backend I decode the token which I receive in the 'authorization' bearer header, to get user's details...

And boom! Here the error message repeats shouting at me: "JsonWebTokenError: invalid signature"

That doesn't happen on the production website, even though the remote backend is one link for both the production and development.

What I have tried and explored

What I noticed using JWT token debugger is that

  1. In case of the production website's request, which doesn't give any errors, the decoded user consists of { id, role }. As EXPECTED. screenshot of the jwt decoder
  2. But in case of local version's request, which gives error message, it shows that the user consists of the whole user details object stored in the DB. And debugger also changes the decryption algorithm automatically from HS256 to HS512. And, even though showing the encrypted message, it says 'token verification failed'. JWT token debugger

Token from local, gives error: eyJhbGciOiJIUzUxMiJ9.eyJlbWFpbCI6ImdtYWlsQGdtYWlsLmNvIiwiYWNjZXNzVG9rZW4iOiJCZWFyZXIgZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmZhV1FpT2lJMk1UZGpNV0V6TjJFd1lqQXpNakV4TnpFMU0yUTBOek1pTENKeWIyeGxJam9pZFhObGNpSXNJbWxoZENJNk1UWXpOakk1TURrME1Td2laWGh3SWpveE5qTTJNemMzTXpReGZRLmI1YTQ3bF9rcVQ5YUhDVGhFM3VtVFZJOTZZSnpkdkJaZHQxN3hMTFJPU1EiLCJ1c2VyIjp7Il9pZCI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3MyIsImZpcnN0TmFtZSI6IiIsImxhc3ROYW1lIjoiIiwiZW1haWwiOiJnbWFpbEBnbWFpbC5jbyIsInJvbGUiOiJ1c2VyIiwiam9iUm9sZSI6IiIsInZpZGVvR29hbCI6IiIsInByb2ZpbGVQaWN0dXJlIjoiIiwiYXBwcm92YWwiOnsiaXNBcHByb3ZlZCI6dHJ1ZSwidHJ4SWQiOiIifSwiYWNjZXNzVHlwZSI6eyJicmFuZGluZzEiOnRydWUsImJyYW5kaW5nMiI6dHJ1ZSwiYnJhbmRpbmczIjp0cnVlLCJicmFuZGluZzQiOnRydWUsInNjcmlwdCI6dHJ1ZSwidGVtcGxhdGUiOnRydWUsImZ1bGxBY2Nlc3MiOnRydWV9LCJyZXNldFBhc3NUb2tlbiI6IiIsImJyYW5kaW5nIjp7ImJyYW5kaW5nMSI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NCIsImJyYW5kaW5nMiI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NSIsImJyYW5kaW5nMyI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NiIsImJyYW5kaW5nNCI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NyJ9LCJzdWJfc3RhdHVzIjoyfSwiaWF0IjoxNjM2MjkxNTk0LCJleHAiOjE2Mzg4ODM1OTR9.ZCnnNZ2a7aeO6GCnyhnWYGMX-4kkJX75ZyzG52lSiWxUBIawXrA37882HFwo_3r6-I3JrrYNv270vxfsMwyBlw


Token from production, works as expected : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MTdjMWEzN2EwYjAzMjExNzE1M2Q0NzMiLCJyb2xlIjoidXNlciIsImlhdCI6MTYzNjI5MTY3MywiZXhwIjoxNjM2Mzc4MDczfQ.bqY6y0_lmX5dBAHemgv_9UFuupwLBBDcyFpAdXgCiH8


JWT Secret : jdgfaiodsugfaileufliaeruy


Code of decoding token and getting user data is:

exports.requireSignin = (req, res, next) => {
  if (req.headers.authorization) {
    const token = req.headers.authorization.split(" ")[1];
    console.log( 'token is', token );
    jwt.verify(token, process.env.JWT_SECRET, function (err, decoded) {
      if (err) {
        console.log( err, 'Token given', token, 'Token secret', process.env.JWT_SECRET );
        return res.status(401).json({ error: "Token has been expired!" });
      }
      req.user = decoded;
      console.log( decoded );
    });
    // const user = jwt.verify(token, process.env.JWT_SECRET);
    // console.log(user);
    // req.user = user;
  } else {
    return res.status(401).json({ error: "Authorization required" });
  }
  next();
  //jwt.decode()
};

Code of GENERATING that token:

exports.signin = async (req, res) => {
  
  
  User.findOne({ email: req.body.email }).exec((error, user) => {
    if (error){ console.log( 'login error', error ); return res.status(400).json({ error }); }
   
    if (user) {
      bcrypt.compare(req.body.password, user.hash_password, (err, result) => {
        if (err) {
            console.log( req.body.password, user.hash_password );
          return res
            .status(400)
            .json({ error: "Something's wrong, Please try again" });
        }
        if (!result) {
          return res.status(400).json({ error: "Invalid credentials" });
        }

        if (user.approval.isApproved === false)
          return res
            .status(400)
            .json({ error: "Please verify your account" });

        if (user.isSuspended === true)
          return res.status(400).json({ error: "You have been temporarily suspended, please contact support" });

        const token = jwt.sign(
          { _id: user._id, role: user.role },
          process.env.JWT_SECRET,
          {
            expiresIn: "1d",
          }
        );
        console.log( process.env.JWT_SECRET, token, user._id, user.role );

        // some unnecessary code ...

          res.status(200).json({
            success: true,
            token: "Bearer " + token,
            ProfileImageBaseUrl: ProfileImageBaseUrl,
            user: {
              _id,
              firstName,
              lastName,
              email,
              role,
              jobRole,
              videoGoal,
              profilePicture,
              createdBy,
              approval,
              accessType,
              resetPassToken,
              branding,
              sub_status
            },
          });

           
            
        })
       
      });
    } else {
      return res.status(400).json({ error: "Something's wrong, Please try again" });
    }
  });
};

A) WHEN I GET AN ERROR, The LOGS I receive from my backend are:


Sign in controller, console.log( process.env.JWT_SECRET, token, user._id, user.role ) is

jdgfaiodsugfaileufliaeruy eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MTdjMWEzN2EwYjAzMjExNzE1M2Q0NzMiLCJyb2xlIjoidXNlciIsImlhdCI6MTYzNjI5MTY3MywiZXhwIjoxNjM2Mzc4MDczfQ.bqY6y0_lmX5dBAHemgv_9UFuupwLBBDcyFpAdXgCiH8 617c1a37a0b032117153d473 user


Require sign in controller ,console.log( err, 'Token given', token, 'Token secret', process.env.JWT_SECRET ) is:

Token given eyJhbGciOiJIUzUxMiJ9.eyJlbWFpbCI6ImdtYWlsQGdtYWlsLmNvIiwiYWNjZXNzVG9rZW4iOiJCZWFyZXIgZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmZhV1FpT2lJMk1UZGpNV0V6TjJFd1lqQXpNakV4TnpFMU0yUTBOek1pTENKeWIyeGxJam9pZFhObGNpSXNJbWxoZENJNk1UWXpOakk1TURrME1Td2laWGh3SWpveE5qTTJNemMzTXpReGZRLmI1YTQ3bF9rcVQ5YUhDVGhFM3VtVFZJOTZZSnpkdkJaZHQxN3hMTFJPU1EiLCJ1c2VyIjp7Il9pZCI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3MyIsImZpcnN0TmFtZSI6IiIsImxhc3ROYW1lIjoiIiwiZW1haWwiOiJnbWFpbEBnbWFpbC5jbyIsInJvbGUiOiJ1c2VyIiwiam9iUm9sZSI6IiIsInZpZGVvR29hbCI6IiIsInByb2ZpbGVQaWN0dXJlIjoiIiwiYXBwcm92YWwiOnsiaXNBcHByb3ZlZCI6dHJ1ZSwidHJ4SWQiOiIifSwiYWNjZXNzVHlwZSI6eyJicmFuZGluZzEiOnRydWUsImJyYW5kaW5nMiI6dHJ1ZSwiYnJhbmRpbmczIjp0cnVlLCJicmFuZGluZzQiOnRydWUsInNjcmlwdCI6dHJ1ZSwidGVtcGxhdGUiOnRydWUsImZ1bGxBY2Nlc3MiOnRydWV9LCJyZXNldFBhc3NUb2tlbiI6IiIsImJyYW5kaW5nIjp7ImJyYW5kaW5nMSI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NCIsImJyYW5kaW5nMiI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NSIsImJyYW5kaW5nMyI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NiIsImJyYW5kaW5nNCI6IjYxN2MxYTM3YTBiMDMyMTE3MTUzZDQ3NyJ9LCJzdWJfc3RhdHVzIjoyfSwiaWF0IjoxNjM2MjkxNTk0LCJleHAiOjE2Mzg4ODM1OTR9.ZCnnNZ2a7aeO6GCnyhnWYGMX-4kkJX75ZyzG52lSiWxUBIawXrA37882HFwo_3r6-I3JrrYNv270vxfsMwyBlw Token secret jdgfaiodsugfaileufliaeruy


B) When no error, these are:


Require sign in : token is eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MTdjMWEzN2EwYjAzMjExNzE1M2Q0NzMiLCJyb2xlIjoidXNlciIsImlhdCI6MTYzNjI5MTYyNSwiZXhwIjoxNjM2Mzc4MDI1fQ.K-inQfI77mepKjkG_5g4obr3sfcVnDwCOXeQlDPra00


Sign in :

jdgfaiodsugfaileufliaeruy eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MTdjMWEzN2EwYjAzMjExNzE1M2Q0NzMiLCJyb2xlIjoidXNlciIsImlhdCI6MTYzNjI5MTYyNSwiZXhwIjoxNjM2Mzc4MDI1fQ.K-inQfI77mepKjkG_5g4obr3sfcVnDwCOXeQlDPra00 617c1a37a0b032117153d473 user

My thoughts

I feel like it is just something simple I just don't notice, I've been trying to fix it for 9 hours, but I haven't determined what yet.

Please, help me, guys!

Any help or hints are highly appreciated!

Thank you so much in advance!

Upvotes: 1

Views: 2237

Answers (1)

Mila A
Mila A

Reputation: 569

Thanks everyone who helped me with this! @Bergi and @eol!

The problem was nextauthjs specific and not conserned about expressjs, as it appeared.

So I don't get token returned by nextauthjs anymore.

Instead, I get token from user object's authToken property, stored in the session.


So it is like:

MyApp.getInitialProps = async ({ router, ctx }) => {
  const session = await getSession(ctx);
  if (router.asPath === '/login' || router.asPath === '/register') {
    return { session: session };
  }
  if (!session || !session.user) {
    ctx.res.writeHead(302, {
      Location: '/login',
    });
    ctx.res.end();
  }
  console.log('Access token', session.accessToken);
  axios.defaults.headers.common = {
    authorization: `${session.accessToken}`,
  };
  return { token: `${session.accessToken}`, session: session };
};

Upvotes: 1

Related Questions