Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticating node API with passport-jwt

I'm trying to setup JWT authentication using passport-jwt. I think I've taken the right steps, but a test GET won't succeed and I don't know how to debug it.

Here's what I've done:

  1. setup passport-jwt straight out of the doc as much as possible

    var jwtOptions = {
        secretOrKey: 'secret',
        issuer: "accounts.examplesoft.com",  // wasn't sure what this was, so i left as defaulted in the doc
        audience: "yoursite.net"   // wasn't sure what this was, so i left as defaulted in the doc
      };
    
    jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeader();
    
    passport.use(new JwtStrategy(jwtOptions, function(jwt_payload, done) {
      User.findOne({id: jwt_payload.sub}, function(err, user) {
        if (err) {
            return done(err, false);
        }
        if (user) {
            done(null, user);
        } else {
            done(null, false);
            // or you could create a new account
        }
      });
    }));
    
  2. Added a token result to my user /login endpoint

    var jwt = require('jsonwebtoken');
    // ...
    
    exports.postLogin = function(req, res, next) {
      passport.authenticate('local', function(err, user, info) {
        if (err) throw err;
        if (!user) {
            return res.send({ msg: 'Login incorrect' });
        }
        req.logIn(user, function(err) {
            if (err) throw err;
            var secretOrKey = jwtOptions.secretOrKey;
            var token = jwt.sign(user, secretOrKey, {
                expiresIn: 631139040 // 20 years in seconds
            });
            res.send({ user: user, jwtToken: "JWT " + token });
        });
      })(req, res, next);
    };
    

Things were looking good up to here. I can login a user (using passport local auth) and the response was a I hoped...

{ "user": { "_id": "56c8b5bd80d16ef41ec705dd", "email": "[email protected]", "password": "$2a$10$zd ... etc.", "__v": 0, }, "jwtToken": "JWT eyJ0eXAiOiJ .... etc." }

I created an unprotected test route like this...

// in my routes file
app.get('/user/tokenTest', user.tokenTest);

And in my controller, a simple endpoint...

exports.tokenTest = function(req, res) {
    console.log(req.headers);
    res.send("token test!!");
};

And GET-ing that works fine, too.

  1. But then I try to protect that route like this:

    app.get('/user/tokenTest', passport.authenticate('jwt', { session: false }),
        user.tokenTest);
    

After I do that, nothing but sadness. I send a request like this:

curl -k 'https://localhost:3443/user/tokenTest' -H 'Authorization: JWT eyJ0eXAiOiJ... etc.' 

And always, always get a 401:

Unauthorized

Console logs in the controller don't seem to execute, neither does logging in the passport.use strategy method. I've tweaked and tweaked, but I'm a little lost. The passport-jwt doc just supplies the example, and virtually no other help.

Please, any ideas about either a mistake that I'm making above, or at least how to go about debugging??

like image 977
user1272965 Avatar asked Feb 20 '16 20:02

user1272965


People also ask

Can I use passport with JWT?

A Passport strategy for authenticating with a JSON Web Token. This module lets you authenticate endpoints using a JSON web token. It is intended to be used to secure RESTful endpoints without sessions.

How do I authenticate API using JWT token?

To authenticate a user, a client application must send a JSON Web Token (JWT) in the authorization header of the HTTP request to your backend API. API Gateway validates the token on behalf of your API, so you don't have to add any code in your API to process the authentication.

Which is better JWT or passport?

JSON Web Token and Passport can be primarily classified as "User Management and Authentication" tools. JSON Web Token and Passport are both open source tools. It seems that Passport with 15.9K GitHub stars and 936 forks on GitHub has more adoption than JSON Web Token with 2.59K GitHub stars and 259 GitHub forks.


1 Answers

For any poor soul that follows me here: the passport-jwt doc implies that the auth header should look like this...

Authorization: JWT JSON_WEB_TOKEN_STRING.....

That turned out to be misleading (for me, anyway).

Fortunately, thanks to this article I was able to learn how the token is built. (The token's prefix up to the first '.' is the base64 encoding of the scheme. That "JWT " at the front was noise that prevented the validation from working.

So the fix was to change the token returned by the user controller from:

    res.send({ user: user, jwtToken: "JWT " + token });

To the simpler:

    res.send({ user: user, jwtToken: token });

Phew. Is it me, or is it really a bummer how inadequately these things are explained in so many node package docs??

like image 58
user1272965 Avatar answered Sep 23 '22 13:09

user1272965