Save Token in local Storage using node

23,067

Solution 1

You do not need to save and check the token from the database. This token such a mechanism can be decoded with only your-server, and if it was done that the token is valid. The code that you want to do should look like.

var cookieParser = require('cookie-parser')
app.use(cookieParser())

app.get('/login', function(req, res, next) {
  var user = {name:'test'}; //!! find the user and check user from db then

    var token = jwt.sign(user, 'secret', {
            expiresInMinutes: 1440
          });

    res.cookie('auth',token);
    res.send('ok');

});

app.use(function(req, res, next) {

  var token = req.cookies.auth;

  // decode token
  if (token) {

    jwt.verify(token, 'secret', function(err, token_data) {
      if (err) {
         return res.status(403).send('Error');
      } else {
        req.user_data = token_data;
        next();
      }
    });

  } else {
    return res.status(403).send('No token');
  }
});

Here you can find very nice article : https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens

Solution 2

I would recommend checking this out if you want local storage: https://www.npmjs.com/package/node-localstorage

But, with that said, you guys and girls wouldn't believe how long it took me to find res.cookie('auth' token) from the above answer. I scoured Google for hours, Passport docs, Express docs, GraphQL and authentication/authorization docs in an effort to find out how to get the token to the API in a stateless manner.

I already built JWT token security and secured my GraphQL resolvers with it, but then, I opted to use EJS along with graphql-request (approx same as Apollo Client), so I needed to find a way to pass the token to my middleware without using a server side session.

Storing a JWT token in cookies is fine especially if you take extra precautions such as signing the cookie, and I recall there are also options you can include that keep the cookie secure, so that other sites cannot see it if the "browser" allows access to cookies. If a cookie is signed with your server secret, the data inside the cookie simply cannot be altered and still be valid. The risk is always still someone leaking their token/cookie, and if that bothers you, do research into refresh tokens. However, API tokens are generally and should be kept tightly secret and safe. Your biggest annoyance will more likely be the requirement to maintain a blacklist of JWTs that expire a year from now if you set expiry to 1y.

I am just including my findings here because this question is actually a rare resource it seems...

Here is my Express middleware for authentication:

 // AUTHENTICATION
 app.use(async (req) => {
     try {
         const token = req.headers.authorization || req.cookies.auth
         const { person } = await jwt.verify(token, SECRET)
         req.person = person
         return req.next()
     } catch (e) {
         return req.next()
     }
 })
  1. You can see I am setting the token from the header with cookie as fallback. This supports my needs fine and allows me to use really any client with stateless security.
  2. My logged in user is available as req.person in my views and GraphQL resolvers. If req.person is not set, the user is treated as not-logged-in.
  3. I am using return req.next() which is important to note because calling next() without parameters is treated as "clean go-to next middleware and/or proceed to process request". If you include any string or object parameter, it will throw an error that can bubble down to your error handling middleware. You can try it yourself. Put return next('You are not authenticated.') in the catch block and you will see it halt the request before your route.
  4. I use return next() because I handle authorization in the routes and in my resolvers. It allows more flexibility such as facilitating register and login mutations to be accessed by non-authenticated users.

Here is my GraphQL endpoint (I am using Apollo Server):

 app.use('/graphql', bodyParser.json(), graphqlExpress((req) => {
     const context = {
         person: req.person
     }
     return {
         schema,
         context,
         rootValue: null
     }
 }))
  1. In my GraphQL resolvers, the third parameter of every query has context.person populated with req.person which comes from the above Authentication middleware.
  2. That is really all a person needs to know.

Here is how I am using the NPM package called graphql-request: https://www.npmjs.com/package/graphql-request

 app.get('/allpeople', async (req, res) => {
     try {
         const client = new GraphQLClient(GRAPHQL_ENDPOINT, {
             headers: { Authorization: req.headers.authorization || req.cookies.auth }
         })
         const query = `query allPeople($serialNumber: String!) {
             allPeople(serialNumber: $serialNumber) {
                 id
                 created
                 status
                 email
             }
         }`
         const variables = {
             serialNumber: req.person
         }
         const response = await client.request(query, variables)
         res.render('allpeople/list', { people: response.allPeople })
     } catch (e) {
         throw [`allPeople`, `${JSON.stringify(error, null, 2)}`]
     }
 })
  1. I include this code because there are no "more advanced" example usages of graphql-request, and I like it so far. It is very concise and could easily be swapped out for Apollo Client if you venture into React.js. My examples here are also very relevant for anyone researching createNetworkInterface and new ApolloClient().
Share:
23,067
monkeyUser
Author by

monkeyUser

[email protected]

Updated on July 09, 2022

Comments

  • monkeyUser
    monkeyUser almost 2 years

    I'm using JWT ("jsonwebtoken": "^5.4.0") with express 4 and jade. I'm able to create the right Token, but How can i Pass this token in each call? Where I have to store this token ? in headers or in localStorage?

    For now I'm using CURL with Postman, and Set token in header in

    x-access-token
    

    Have I Do create a middleware that retrieve a token from Database and use this in each call?

    thanks