How to store jwt in cookie and pass it to authentication function when redirecting a page?

天涯浪子 提交于 2020-12-05 09:33:24

问题


I have a node.js express backend built with Postman and tested with Jest. I wrote a front end with hbs and the next step is to stitch them. However I still keep getting "please authenticate" error message that's from my auth function, which I guess is because I'm not successfully passing my jwt token.

So on login page (users/login) I want to login with email and password then I want to redirect to me page(users/me) where I can perform other stuff that belongs to this user.

Front-end login page code:

<section class="login-bg">
        <div class="login-form">
            <p>Welcome to Task Manager, please log in!</p>
            <form class="input-group" action="/users/login" method="POST">
                <label>Email:</label>
                <input type="email" name="email" placeholder="type your email" value="{‌{user.email}}" required >
                <label>Password:</label>
                <input type="password" name="password" placeholder="type your password" value="{‌{user.password}}" required>

                <button class="button" type="submit">Log In</button>
            </form>
        </div>
    </section>

Back-end

in middleware/auth.js

const jwt = require('jsonwebtoken')
const User = require('../models/user')

const auth = async (req, res, next) => {
    try {
        const token = req.header('Authorization').replace('Bearer ', '')
        const decoded = jwt.verify(token, process.env.JWT_SECRET)
        const user = await User.findOne({_id: decoded._id, 'tokens.token': token})

        if (!user) {
            throw new Error()
        }

        req.token = token
        req.user = user
        next()

    } catch (error) {
        res.status(401).send({error: 'Please authenticate.'})
    }
}

module.exports = auth

in src/routers/users.js

router.post('/login', async (req, res) => {
    try {
        const user = await User.findByCredentials(req.body.email, req.body.password)
        const token = await user.generateAuthToken()
        res.cookie('jwt',token, { httpOnly: true, secure: true, maxAge: 3600000 })
        res.redirect('/users/me')
    } catch (error) {
        res.status(400).send()
    }
})

However, when I do console.log(document.cookie) in users/me it says undefined.

Then I have the cookie-parser installed and import to app.js, and try to write this part in src/routers/users.js:

router.get('/me', auth, async (req, res) => {
    console.log('Cookies: ', req.cookies)
    try {
        res.render('me', {name: user.name})
    } catch (error) {
        res.status(500).send()
    }
})

but this console doesn't print anything, probably cos I am getting error from auth.

I also have a a js file attached to me page but I have no clue if I could write this way, probably wrong:

const userToken = document.cookie.jwt.token

fetch('/users/me', {
    method: 'POST',
    headers: {
     'Authorization': 'Bearer ' + userToken
    }
})
.then(res => res.json())
.then(data => { console.log(data) })
.catch(err => { console.log(err) })

then in the Network / Headers, I have

Request URL:

http://localhost:3000/users/login

Request Method:

POST

Status Code:

302 Found

Remote Address:

Referrer Policy:

no-referrer-when-downgrade

Response Headers

Connection:

keep-alive

Content-Length:

62

Content-Type:

text/html; charset=utf-8

Date:

Fri, 07 Jun 2019 18:41:47 GMT

Location:

/users/me

Set-Cookie:

jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Y2Y2NjNlMTQwMTQyYjE0MzhmZTJjNDMiLCJpYXQiOjE1NTk5MzI5MDd9.T_P8O-j98cs9gtahTzspJjx1qNMSe3M5OAySyeH25fs; Max-Age=3600; Path=/; Expires=Fri, 07 Jun 2019 19:41:47 GMT; HttpOnly; Secure

Vary:

Accept

X-Powered-By:

Express

There is no request cookies, only response cookies. I am not sure what those means...@_@

I want to pass the jwt to successfully login and render the me page properly, how could I do that?


回答1:


Your jwt token cookie does not work because it declares flag secure: true in the following code:

res.cookie('jwt',token, { httpOnly: true, secure: true, maxAge: 3600000 })

which lead to Secure flag in HTTP response, indicating this cookie is only available under HTTPS environment:

Set-Cookie:
jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Y2Y2NjNlMTQwMTQyYjE0MzhmZTJjNDMiLCJpYXQiOjE1NTk5MzI5MDd9.T_P8O-j98cs9gtahTzspJjx1qNMSe3M5OAySyeH25fs; 
Max-Age=3600; Path=/; 
Expires=Fri, 07 Jun 2019 19:41:47 GMT; HttpOnly; Secure

As your request URL is using HTTP (http://localhost:3000/users/login), the cookie would be ignored by browser.




回答2:


First: you can't view the cookie on client side because you set the following ({ secure:true, httpOnly:true}) -secure means it should only use the cookie over an https network while -httpOnly means the cookie should be read by any client side Javascript..

Second: did you really add the "Authorization" header after generating the jwt or you just put it in a cookie 🤔

If so, then try:

jwt.verify(token, <your secret>).then(user=> console.log(user)).catch(err=>console.log(err.toString());

For those who may run into same problem in the future




回答3:


From express-session docs:

Only set the secure tag if you're in production.

    if (app.get('env') === 'production') {
      app.set('trust proxy', 1) // trust first proxy
      sess.cookie.secure = true // serve secure cookies
    }


来源:https://stackoverflow.com/questions/56524264/how-to-store-jwt-in-cookie-and-pass-it-to-authentication-function-when-redirecti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!