0

Trying to implement the Passport-jwt strategy, I've got it working if I use a string as a 'secret', but I'm struggling to convert it to use a public/private key pair. I've probably made a simple mistake with the keys, but I don't understand what that is.

The login route provides me with a signed token with the pub/priv keys, but is always 'unauthorised' when I try the '/auth/test' route (whereas with the string secret is works)

The code below works, with the non-working code for the pub/priv key code highlighted/commented out.

Any help or comments appreciated!

./controllers/auth.js

exports.login = (req, res, next) => {
    (async() => {
        try {
            const user = await User.findOne({ where: {email: req.body.email} });
            if(!user) {
                res.status(401).json({ success: false, message: "Bad Username/Password" });
            }

            const isValid = await bcrypt.compare(req.body.password, user.hashedPassword);

            if(isValid) {
                const tokenObject = utils.issueJWT(user);
                res.status(200).json({ success: true, token: tokenObject.token, expiresIn: tokenObject.expires});
            } else {
                res.status(401).json({ success: false, message: "Bad Username/Password" });
            }

        } catch(err) {
            next(err);
        }
    })();
};

./config/passport.js

...    
const User = require('../models/user');

// ***** Not working
// const pathToKey = path.join(__dirname, '../../../.ssh/', 'jennings.pub');
// const PUB_KEY = fs.readFileSync(pathToKey, 'utf-8');
// *****    

const options = {
    jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
    secretOrKey: 'secret',

    // ***** Not working
    // secretOrKey: PUB_KEY,
    // algorithms: ['RS256']
    // *****
}

function initialize(passport) {
    const authenticateUser = async(jwt_payload, done) => {
        let user;
        try {
            user = await User.findOne({
                where: { id: jwt_payload.sub }
            });
        } catch(e) {
            return done(e, false);
        }

        // No user found
        if(!user) {
            return done(null, false);
        }
        //  User found
        return done(null, user);
    };

    passport.use(new JwtStrategy(options, authenticateUser));
}

module.exports = initialize;

./util/utils.js

// ***** Not working
// const pathToKey = path.join(__dirname, '../../../.ssh/', 'jennings');
// const PRIV_KEY = fs.readFileSync(pathToKey, 'utf-8');
// *****

exports.issueJWT = (user) => {
    const id = user.id;
    const expiresIn = '1h';

    const payload = {
        sub: id,
        iat: Date.now()
    };

    const signedToken = jwt.sign(payload, 'secret', { expiresIn });

    // ***** Not working
    // const signedToken = jwt.sign(payload, 'secret', { expiresIn,  algorithm: 'RS256'});
    // *****

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

The test route

router.get('/test', passport.authenticate('jwt', { session: false }), (req, res, next) => {
    res.status(200).json({ success: true, message: 'get in!' });
});
NickW
  • 1,207
  • 1
  • 12
  • 52

1 Answers1

0

So I found a solution, based off of two other links:

The first here of an identical problem suggesting that the keys have to be in .pem format (but suggesting using an external library),

and here, which tells you to run ssh-keygen -f id_rsa.pub -m 'PEM' -e > id_rsa.pem on the public key to convert it to open-ssl compatible format (the private key is already in .pem format)

That worked for me

NickW
  • 1,207
  • 1
  • 12
  • 52