S
S
sasha_jarvi2020-10-13 16:52:10
JSON Web Token
sasha_jarvi, 2020-10-13 16:52:10

How to solve the problem with authorization through passport.js in a MEVN application (error 401)?

I am working on a MEVN application, I decided to add authorization through passport.js. Registration and authorization are successful, however, when trying to redirect to the home page after authorization, an error occurs 401 Unauthorized. I pass the JWT token in the Authorization header of the AJAX request on the home page, but to no avail. Here is the code server.js:

const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const cors = require('cors');
const morgan = require('morgan');
const fs = require('fs');

const jwt = require('jsonwebtoken');
const passport = require('passport');
const passportJWT = require('passport-jwt');
const ExtractJWT = passportJWT.ExtractJwt;
const JWTStrategy = passportJWT.Strategy;
const jwtOptions = {};
jwtOptions.jwtFromRequest = ExtractJWT.fromAuthHeaderWithScheme('jwt');
jwtOptions.secretOrKey = 'movieratingapplicationsecretkey';

const app = express();
const router = express.Router();

const User = require('./models/User');

app.use(morgan('combined'));
app.use(bodyParser.json());
app.use(cors());
app.use(passport.initialize());

passport.use(new JWTStrategy(jwtOptions, (jwt_payload, done) => {
  User.findOne({ id: jwt_payload.id }, (err, user) => {
    if (err) {
      return done(err, false);
    }

    if (user) {
      return done(null, user);
    } else {
      return done(null, false);
    }
  });
}));

mongoose.connect('mongodb://localhost/movie_rating_app', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
  .then(() => {
    console.log('Connection is established');
  })
  .catch((err) => {
    console.error(`App starting error: ${err.stack}`);
  });

// include controllers
fs.readdirSync('controllers').forEach(file => {
  if (file.substr(-3) === '.js') {
    const route = require(`./controllers/${file}`)
    route.controller(app)
  }
})

router.get('/', (req, res) => {
  res.json({ message: 'API was initialized!' });
});

const port = process.env.API_PORT || 8081;
app.use('/', router);

app.listen(port, () => {
  console.log(`api running on port ${port}`);
});


Code controllers/movies.js:

const Movie = require('../models/Movie')
const Rating = require('../models/Rating')

const passport = require('passport')

module.exports.controller = app => {
  // fetch all movies
  app.get(
    '/movies',
    passport.authenticate('jwt', { session: false }),
    (req, res) => {
      Movie.find({}, 'name description release_year genre', (error, movies) => {
        if (error) console.error(error)

        res.send(movies);
      })
  })

  // fetch a single movie
  app.get('/movies/:id', (req, res) => {
    Movie.findById(req.params.id, 'name description release_year genre', (error, movie) => {
      if (error) console.error(error)

      res.send(movie);
    })
  })
}


Code controllers/users.js:

const User = require('../models/User');

const passportJWT = require('passport-jwt');
const jwt = require('jsonwebtoken');

const ExtractJwt = passportJWT.ExtractJwt;
const jwtOptions = {};
jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt');
jwtOptions.secretOrKey = 'thisisthesecretkey';

module.exports.controller = app => {
  // register a user
  app.post('/users/register', (req, res) => {
    const newUser = new User({
      name: req.body.name,
      email: req.body.email,
      password: req.body.password,
    })

    User.createUser(newUser, (error, user) => {
      if (error) {
        res.status(422).json({
          message: 'Something went wrong. Please try again after some time'
        })
      }

      res.send({ user });
    })
  })

  // login user
  app.post('/users/login', (req, res) => {
    if (req.body.email && req.body.password) {
      const email = req.body.email,
        password = req.body.password;

      User.getUserByEmail(email, (err, user) => {
        if (!user) {
          res.status(404).json({ message: 'The user does not exist' })
        } else {
          User.comparePassword(password, user.password, (error, isMatch) => {
            if (error) throw error;

            if (isMatch) {
              const payload = { id: user.id };
              const token = jwt.sign(payload, jwtOptions.secretOrKey);
              res.json({ message: 'ok', token })
            } else {
              res.status(401).json({ message: 'The password is incorrect' })
            }
          })
        }
      })
    }
  })
}


Script from component Home.vuecontaining AJAX request

<script>
import axios from 'axios';
import MovieCard from '@/components/MovieCard.vue';

export default {
  name: 'Home',
  components: {
    MovieCard,
  },
  data: () => ({
    movies: [],
  }),
  mounted() {
    this.fetchMovies();
  },
  methods: {
    async fetchMovies() {
      const token = window.localStorage.getItem('auth');

      return axios({
        method: 'get',
        url: 'http://localhost:8081/movies',
        headers: {
          Authorization: `JWT ${token}`,
          'Content-Type': 'application/json',
        },
      })
        .then((response) => {
          console.log(response);
        });

      // return axios.get('http://localhost:8081/movies')
      //   .then(({ data }) => {
      //     this.movies = data;
      //   })
      //   .catch((error) => {
      //     console.error(error);
      //   });
    },
  },
};
</script>


I tried different methods to solve this problem, for example, changed ExtractJWT.fromAuthHeaderWithScheme('jwt')to ExtractJWT.fromAuthHeaderWithScheme('bearer'), but it did not help. How to fix 401 error?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question