2

I dont know if this has been asked before, but i feel like ive scoured the internet and found close to nothing on the topic.

Im quite new to node and JWT but what i want to do is to generate a JWT and then store it in the Authorization header so that i can access it from the backend and send it to the frontend. It should look something like "Authorization: Bearer TOKEN".

Im also using passport and passport-jwt to authorise the user, so when doing something like

res.setHeader('authorization', 'Bearer ' + token');

I get this error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. Because passport has already redirected the response maybe?

When i searched for an answer it seemed like most people just used postman or rest as an example and assumed that we would find how to add the token to the headers ourselves. Im guessing its straightforward, but what am i missing?

Here is my code

postLogin = async (req, res, next) => {
    await passport.authenticate('local', { //Authenticate user
        successRedirect: '/',
        failureRedirect: '/users/login',
        failureFlash: 'Username or Password incorrect'
    })(req, res, next);

    const user = await User.findOne({ email: req.body.email });
    const token = await auth.generateAccessToken(user.toObject());

    res.setHeader('Authorization', 'Bearer ' + token); //Save accesstoken to authorization header
    console.log(headers);
}

and

const generateAccessToken = async (user) => {
    return new Promise((resolve, reject) => {
        jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, {
            expiresIn: '30s'
        }, 
        (err, token) => {
            if (err) 
                reject(err);
            else {
                console.log(`Someone generated token: ${token}`);
                resolve(token);
            }
        });
    });
}

Thanks in advance :D

1 Answers1

0

Your code is trying to set a header after Passport is already sending headers itself. Rather than passing redirect options to passport.authenticate as an object, you can pass functions to do custom logic. See the example.

Zac Anger
  • 6,983
  • 2
  • 15
  • 42
  • Thanks! There's another problem now though, because ```res.setHeader('authorization', 'Bearer ' + token);``` doesn't actually seem to set the header. I can't access it through ```req.headers.authorization```, even when I'm on the same page. Does it have a wierd scope or do I need to do something else to access the header? – flurp.potatis Jan 08 '21 at 18:12
  • Does `res.set` (rather than `setHeader`) behave the same way? `res.set` is the express method, `res.setHeader` is exposing the method on the native Node response object (and `res.header` is the same as `res.set`). – Zac Anger Jan 08 '21 at 18:17
  • Yes it does. However I seem to be able to access the header through ```res.getHeader('authorization')``` but only if I'm on the same page as the ```res.set()``` or ```res.setHeader()```. Do I need to do something on the front-end or back-end so that I could access the token in other routes? Thanks for the quick respone:D – flurp.potatis Jan 08 '21 at 18:29
  • Is the client doing anything to store that authorization header, for example as a cookie? That's how it would keep the same token across pages and requests. Alternatively, the server could use `res.cookie` to set that for the client, and the client could either turn its cookies into authorization headers, or the server could do all the work by using `req.cookie` to check the token. https://expressjs.com/en/api.html#res.cookie – Zac Anger Jan 08 '21 at 18:32
  • No I have not done that and yes that works, but it doesn't synthesize well with my other code. You mention turning my cookies into an authorization header (which after doing some more research turns out is equivalent to localStorage?), how would I do that? Is there a drawback to using just cookies? Thank you for all your helpfull advice. – flurp.potatis Jan 08 '21 at 21:10
  • Ahh okay, yeah, there's more parts to it than just sending the authorization header. Cookies and localstorage aren't the same thing, but they are both types of browser storage. The biggest drawback to only using cookies is that if you end up supporting mobile clients from the same server in the future, you'll have to support the authorization header anyway, since mobile apps don't use cookies. It's kind of a toss-up which way is better to go though (cookie handling server side, or sending and looking for the auth header and turning that into cookies client-side). – Zac Anger Jan 08 '21 at 21:16
  • But if I understand you correctly, at the end of the day, I will have to convert the authorization headers to cookies on the front-end or back-end depending on which direction I go? Is there a documentation or a guide anywhere to the other parts of recieving the header and turning it into cookies client-side? – flurp.potatis Jan 08 '21 at 23:01
  • Yes, correct. The browser needs to store that somehow, and cookies are the usual way. If you're doing it server-side, you could send both (authorization and set the cookie), and always look for either header during auth checks. Client side, setting cookies is simple: https://stackoverflow.com/a/17521905/5774952, and parsing headers is almost as simple: https://stackoverflow.com/a/58791949/5774952 – Zac Anger Jan 08 '21 at 23:06
  • 1
    Thank you man, really appreciate the help :D – flurp.potatis Jan 09 '21 at 00:52
  • No problem at all! – Zac Anger Jan 09 '21 at 00:57