AleDG
AleDG

Reputation: 84

Authentication header using bearer scheme for JWT

I am building an authentication system for a website in NodeJS using Express, Passport and jsonwebtoken. I have searched everywhere but I cannot find the solution to a problem.

Right now I have an authentication controller:

module.exports = function() {  
var strategy = new BearerStrategy(params, function(payload, done) {
    var decodedToken = jwtDecode(payload)
    db.default.Account.find({where: {id: decodedToken.id}}).then(account =>{
        if (account) {
            return done(null, {
                id: account.id,
                role: account.role
            })
        } else {
            return done(new Error("User not found"), null)
        }
    })
})

passport.use(strategy)
return {
    initialize: function() {
        return passport.initialize()
    },
    authenticate: function() {
        return passport.authenticate("bearer", cfg.jwtSession)
    }
   }
}

In which I use a BearerStrategy and this code works, since my /login route crates a token for the user and returns that token

  accountController.post("/login", function(req, res) {
     if (req.body.email && req.body.password) {
     var accEmail = req.body.email
     var accPassword = req.body.password
     db.default.Account.find({where: {email: accEmail, password: 
       accPassword}}).then(account =>{
     if (account) {
        var payload = {
           id: account.id,
           role: account.role
      }
      var token = jwt.sign(payload, cfg.jwtSecret)
      console.log(token)
      res.status(200).json({
          token: 'Bearer ' + token
      })
       } else {
         res.sendStatus(401)
     }
   })
 } else {
     res.sendStatus(401)
   }
})

If I use Postman to send an HTTP request trying to access the route /account and I set as header the token created everything works fine.

accountController.get('/account', auth.authenticate('bearer', { session: false }), function(req, res){
res.status(200).render('pages/homepage')
})

The question I haven't been able to answer is: It is not enough to send the token back with res.json({token: token}), the token needs to be stored somewhere, right? How should I store the token using a RestAPI, and moreover, how should I send the token from the client-side inside the HTTP header in each request?

I am open to suggestions on how to make this connection between storing and sending the JWT (since generation and validation of the JWT work) thank you

Upvotes: 0

Views: 2573

Answers (1)

Mika Sundland
Mika Sundland

Reputation: 18969

Yes, it's enough to send the token like that. You just have to make sure the client receives the token somehow. In your particular case, the client would send a POST request to the /login endpoint, and read the token from the response to the request. In semi-pseudo code (client-side Javascript):

http.post('/login', (response) => {
  let token = response.split(' ')[1];
});

The client stores the token. It's stored either in localStorage, sessionStorage or in a cookie. There are pros and cons for the various storage places. The client has to be programmed to store it in one of those places, and the server does not store it at all. If you are using a front-end framework such as Angular or React you can find plenty of information and examples using Google and search words such as "angular, jwt, storing". If you are using vanilla JS you can follow the examples in the provided links. Building on the semi-pseudo code above:

http.post('/login', (response) => {
  let token = response.split(' ')[1];
  localStorage.setItem('token', token);
});

The token is sent together with every request in an HTTP header called Authorization. The header should have the following format

Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

The ey... stuff is the actual token. In your case, you might have to use bearer (non-capitalized b), because you've set up Passport to have it that way. You could also make it auth.authenticate('Bearer', ... in your code to make it more "correct". In older documents and blog posts you can often see JWT instead of Bearer, but that doesn't really follow the de-facto standard.

Passport should read the token correctly if you send it that way.

How you add the Authorization header in the client depends on whether you are using a framework or not, and whether the client is a browser or not. If you are using vanilla JS you can read this link. If you are using a framework, you can google "set authorization header, angular" or something similar. There is usually plenty of information in both the official documentation and in blog posts. The part of the code that adds the Authorization field is often called an auth interceptor if you are using a front-end framework. Interceptors are kind of like middleware.

Finally, you are writing this:

How should I store the token using a RestAPI...

REST doesn't really care about how the token is stored. It's done on the client side and has nothing to do with REST. However, REST cares about what the endpoints are named. Is /login really the correct name if it is a verb? The question is asked and answered here.

Upvotes: 2

Related Questions