简体   繁体   中英

PassportJS Validates Expired JWT

the crux of my issue is that PassportJS appears to be validating a JWT which should be invalid as the current time exceeds the exp parameter .

I have provided the relevant code snippets and an explaination of what I think should be happening (although it clearly isn't!!)

The code

// In server.js
// ...
const passport = require("passport");
// ...

require("./config/passport")(passport);
app.use(passport.initialize());

// ...
// In token.js (used to issue JWT)
const jsonwebtoken = require("jsonwebtoken");
// ...

const issueJWT = (user) => {
  const _id = user._id;
  const expiresIn = 30000; // 30s for testing purposes
  const payload = {
    sub: _id,
    iat: Date.now(),
  };

  const signedToken = jsonwebtoken.sign(payload, PRIV_KEY, {
    expiresIn: expiresIn,
    algorithm: "RS256",
  });

  return {
    token: "Bearer " + signedToken,
    expires: expiresIn,
  };
};
// In passport.js
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
// ...

const options = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: PUB_KEY,
  algorithms: ["RS256"],
};

module.exports = (passport) => {
  passport.use(
    new JwtStrategy(options, (jwt_payload, done) => {
      User.findOne({ _id: jwt_payload.sub }, (err, user) => {
        if (err) {
          return done(err, false);
        }
        if (user) {
          return done(null, user);
        } else {
          return done(null, false);
        }
      });
    })
  );
};
// In routes.js
// ...
const passport = require("passport");
const { authenticateWithAccessToken } = require("../controllers/usersController");
// ...
router
  .route("/authenticate-with-access-token")
  .get(
    passport.authenticate("jwt", { session: false }),
    authenticateWithAccessToken
  );
// In usersController.js
exports.authenticateWithAccessToken = async (req, res, next) => {
  try {
    const user = req.user;

    res.status(200).json({
      success: true,
      name: user.name,
      email: user.email,
    });
  } catch (err) {
    next(err);
  }
};

Sample payload

{
 alg: "RS256",
 typ: "JWT"
}.
{
 sub: "5eec9f1c4a416c1e50fc0a8e", // user._id
 iat: 1593258411458,              // 2020-06-27 11:46:51
 exp: 1593258441458               // 2020-06-27 11:47:21
}.
[signature]

What I would expect to happen

  1. Client sends GET request to /authenticate-with-access-token with Bearer token (JWT) in auth header
  2. PassportJS (via jsonwebtoken.verify() ) attempts to verify JWT but finds that Date.now() exceeds the expiry on the JWT
  3. PassportJS raises an error, resolving the request with a 401 Unauthorized response

What does happen

  1. Client sends GET request to /authenticate-with-access-token with Bearer token (JWT) in auth header
  2. PassportJS passes the user object into the request body and calls next()
  3. Final piece of middleware runs, resolving the request with a 200 OK response and passes the user details back via a JSON body

I'm sure I'm missing something obvious but for the life of me I cannot figure out what is going on. Thanks for any help in advance!

Ok so I figured it out!

Turns out (from looking at examples on the jsonwebtoken documentation) that the iat property used when signing the token should be in seconds rather than miliseconds. Therefore the Date.now() in tokens.js should actually be Math.floor(Date.now / 1000) :

// In token.js (used to issue JWT)
const jsonwebtoken = require("jsonwebtoken");
// ...

const issueJWT = (user) => {
  const _id = user._id;
  const expiresIn = 30; // 30s for testing purposes

  const payload = {
    sub: _id,
    iat: Math.floor(Date.now() / 1000),
  };

  const signedToken = jsonwebtoken.sign(payload, PRIV_KEY, {
    expiresIn: expiresIn,
    algorithm: "RS256",
  });

  return {
    token: "Bearer " + signedToken,
    expires: expiresIn,
  };
};

I think you should set the Maxage of the jwt token in the options object since passport is verifying the token using jsonwebtoken module, also if you set the ignoreExpiration option to true passport will not validate the expritation of the token, I know this is not the case because I can't see it in your code, but my best guess is that you have to set Maxage in your options like this { expiresIn: '1h' }

from the documentation

jsonWebTokenOptions: passport-jwt is verifying the token using jsonwebtoken. Pass here an options object for any other option you can pass the jsonwebtoken verifier. (ie maxAge)

if you wanna learn more about the jsonwebtoken

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM