6

When a user logs in, i send back a HttpOnly cookie in the response.

enter image description here

However when i try to read the cookies when i make a subsequent call to the API, there is nothing

Here is how i made the cookie:

var signOptions = {
    expiresIn: '30d',
    algorithm: 'RS256'
  }
  var CurrentDate = new Date()
  CurrentDate.setMonth(CurrentDate.getMonth() + 1)
  var cookieOptions = {
    httpOnly: true,
    expires: CurrentDate
  }

  const token = jwt.sign({ _id: user._id },
    fs.readFileSync(path.resolve('routes/keys/private.key'), 'utf8'),
    signOptions)

  res.status(200).cookie('stickyAccessJwt', token, cookieOptions).send('well done')

Route ('/test'):

const express = require('express')
const router = express.Router()
const { CheckAuthorisation } = require('./middleware/checkAuthorisation')

router.get('/', CheckAuthorisation, async (req, res) => {
  res.send(':)')
})

module.exports = router

Middleware (the 401 is reached here):

let checkAuthorisation = (req, res, next) => {
  var userJWT = req.cookies.stickyAccessJwt
  if (!userJWT) {
    res.status(401).send('Invalid or missing authorization token')
  } else {
    // 2. There's a token; see if it is a valid one and retrieve the payload

    var verifyOptions = {
      expiresIn: '30d',
      algorithm: ['RS256']
    }

    const userJWTPayload = jwt.verify(
      userJWT,
      fs.readFileSync(path.resolve('routes/keys/private.key'), 'utf8'),
      verifyOptions)

    if (!userJWTPayload) {
      // Kill the token since it is invalid
      res.clearCookie('stickyAccessJwt')
      res.status(401).send('Kill the token since it is invalid')
    } else {
      // 3. There's a valid token...see if it is one we have in the db as a logged-in user
      User.findOne({ '_id': userJWTPayload._id })
        .then(function (user) {
          if (!user) {
            res.status(401).send('User not currently logged in')
          } else {
            console.log('Valid user:', user.email)
            next()
          }
        })
    }
  }
}

Here is my index.js

const Joi = require('joi')
Joi.objectId = require('joi-objectid')(Joi)
const bodyParser = require('body-parser')
const cors = require('cors')
const cookieParser = require('cookie-parser')
const mongoose = require('mongoose')
const express = require('express')
const app = express()
const register = require('./routes/register')
const login = require('./routes/login')
const test = require('./routes/test')

mongoose.connect('mongodb://localhost/stickywall', { useNewUrlParser: true })
  .then(() => console.log('Now connected to MongoDB!'))
  .catch(err => console.error('Something went wrong', err))
mongoose.set('useCreateIndex', true)

app.use(cors())
app.use(cookieParser())
app.use(express.json())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use('/register', register)
app.use('/login', login)
app.use('/test', test)

const port = process.env.PORT || 4000
app.listen(port, () => console.log(`Listening on port ${port}...`))

I do not understand why req.cookies is empty, is there something i am missing?

srysry
  • 173
  • 1
  • 1
  • 10

2 Answers2

8
  res.cookie([`JWT_TOKEN=Bearer ${token}; secure; httponly; 
  samesite=Strict;`,])
  1. The first thing is to install the cookie-parser library, which is a middleware, so Express somehow can manage cookies:

npm install cookie-parser

  1. Then go where you configure your Express application and add the cookie-parser library as a middleware

    const express = require('express');
    const cookieParser = require('cookie-parser');
    app.use(cookieParser());```
    
    
  2. Now our Express application can do all of the cookie parsing stuff for us!

    req.cookies.JWT_TOKEN

  3. In the front if you use axios you must always set in the configuration "withCredentials: true,"

const config = {
 headers: {
    'Content-Type': 'application/json',
   },
  withCredentials: true
}; 
          
    axios
      .post(
        'http://localhost:3008/api/auth/login',
        {
          username: target.username.value,
          password: target.password.value,
        },
        config
      )
      .then((data) => JSON.stringify(data, null, 2))
      .then((result) => console.log(result))
      .catch((err) => console.log('[Control Error ]', err))
  }

!!! HTTP cookies are sent automatically in all requests to the server. THE END

Joel Carneiro
  • 3,287
  • 3
  • 16
  • 20
Namroy
  • 99
  • 1
  • 3
-1
const token = req.body.token ||
    req.query.token ||
    req.headers['x-access-token'] ||
    req.cookies.token;

if (!token) {
   res.sendStatus(401)
}
ilia
  • 339
  • 8
  • 23
  • 1
    by the way why are you using body-parser if you are using express.json()? or why are you using express.json() when you are using body-parser – ilia Mar 13 '19 at 20:10
  • 2
    Whilst this code snippet is welcome, and may provide some help, it would be [greatly improved if it included an explanation](//meta.stackexchange.com/q/114762) of *how* and *why* this solves the problem. Remember that you are answering the question for readers in the future, not just the person asking now! Please [edit] your answer to add explanation, and give an indication of what limitations and assumptions apply. – Aniket G Mar 14 '19 at 03:55
  • @Jake not sure - i've been working through tutorials and been modifying my code over time. I originally had a token stored in localStorage that i would send over to the server to verify, however reading that that opened up for XSS attacks i went (and am currently) going down the route of using a HttpOnly cookie. do you recommend i use just body-parser? – srysry Mar 14 '19 at 15:02
  • 1
    why didn't mention that you were storing validation token in localStorage, variables in localStorage can be easily changed with javascript and potential attacker would easily perform XSS attack, but maybe you already know this, but if you are going to use httpOnly cookies you are on right way, by the way i see in your code that u are already using httpOnly cookie, that got me confused about what you want to achieve – ilia Mar 14 '19 at 15:07
  • @Jake because i am not storing it in localStorage anymore. did you read my comment? I mentioned XSS attack, also i mentioned httpOnly in the title of this post – srysry Mar 14 '19 at 18:14
  • when you mentioned localStorage (because you mentioned httpOnly before) i got confused. is your problem solved? – ilia Mar 14 '19 at 18:19
  • @jake I'm afraid not :( do I need to do something in particular to make sure it's being sent back to the API? – srysry Mar 15 '19 at 06:54
  • can you show me the code in middleware after if(!token)? maybe you are verifying wrongly – ilia Mar 15 '19 at 10:24
  • @Jake updated the code :) but it fails at the first check so i don't see how the rest of the code matters :( – srysry Mar 16 '19 at 12:05
  • then, try to add return statement at if(!userJWTPayload) to stop process if JWTPayload does not exists – ilia Mar 16 '19 at 12:33
  • Any update to this? Running into the same issue – emarel Jan 27 '21 at 00:24