Problem with building a register and login system with authentication

Hello everyone,
I’m currently learning how to build full stack web applications with register and login systems. The problem I’m facing is as follows:

When a new user registers or an existing user signs in, via the client side, the user is successfully saved in my local mongodb database, along with the auth tokens assigned to them; but when redirecting the user to the main page soon after logging in, the server can’t seem to remember if said user already has an authentication token. So the client side simply responds with “Please Authenticate”
I don’t really know where I’m getting it wrong.

Please find the necessary code below:

auth .js file:

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, 'thisismynewcourse')
        const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })

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

        req.token = token
        req.user = user
        next()
    } catch (e) {
        res.status(401).send({ error: 'Please authenticate.' })
    }
}

module.exports = auth

user router file - registering new user:

router.post('/users', async (req, res) => {
    const user = new User(req.body)

    try {
        await user.save()
        const token = await user.generateAuthToken()
        res.redirect('/users/game-options')
        //res.status(201).send({ user, token })
        
    } catch (e) {
        res.status(400).send(e)
    }
})

user router file - signing in user:

router.post('/users/login', async (req, res) => {
    try {
        const user = await User.findByCredentials(req.body.email, req.body.password)
        const token = await user.generateAuthToken()
        res.redirect('/users/game-options')
        //res.send({ user, token })
    } catch (e) {
        res.status(400).send()
    }
})

game-options-redirect:

router.get('/users/game-options', auth, async (req, res) => {
    
    res.render('main.ejs')
})

database screenshot:

From the database screenshot, you can see that the user already has multiple tokens, but the client side keeps responding with “please authenticate”

Client side screenshots:

Kindly let me know where I’m getting it wrong.

After you register/login a user you need to save the generated token in the client. You can use cookies or local storage for that purpose. Then you can append the token to the authorization header on the following requests.

My personal recommendation is to save the token in a cookie and extract it from there. That will make things much easier.

I’ll leave you two files from a project where I used JWT authentication:
Auth middleware
Login

Hey csibanda,

Definitely look into what @kelvinsanchez15 has mentioned.

I just wanted to add: Something to help your debugging would be to use the caught errors in your try...catch blocks. Even just console.error(e) is enough.

Thanks very much @Sky020

Thank you very much @kelvinsanchez15

Sorry again @kelvinsanchez15,
But is there anything else I can add to this handler; the go to route after the user has been logged in?

router.get('/users/game-options', auth, async (req, res) => {
    
    res.render('main.ejs')
})

The above route is where the user gets redirected to after logging in.

Sorry again @Sky020 ,
But is there anything else I can add to this handler; the go to route after the user has been logged in?

router.get('/users/game-options', auth, async (req, res) => {
    
    res.render('main.ejs')
})

The above route is where the user gets redirected to after logging in.

Your game-options route makes use of an auth middleware (auth.js) that is running first to check if the user is authenticated.

router.get('/users/game-options', auth, async (req, res) => {
    
    res.render('main.ejs')
})

You are getting a 401 error (Please authenticate) because the middleware is not receiving a valid token.

auth.js file:

const auth = async (req, res, next) => {
    try {
        // Here your token is undefined because it doesn't exist in the header
        const token = req.header('Authorization').replace('Bearer ', '')
        // Then JWT try to verify the token but fails and throws an error
        const decoded = jwt.verify(token, 'thisismynewcourse')
        ...

By solving the tokens problem (saving and retrieving) you are allowed to redirect the user to any protected route.

1 Like