Express.js, сервер отвечает Unauthorized, но пользователь авторизован

Проект(обучаюсь): https://github.com/mihinov/crm-angular

У меня есть index.js, в нём я подключаю основное приложение app.js

const app = require('./app');
const port = process.env.PORT || 5000;

app.listen(port, () => console.log(`Server has been started on http://localhost:${port}`));

app.js, подключение всех роутов:

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

const authRoutes = require('./routes/auth');
const analyticsRoutes = require('./routes/analytics');
const categoryRoutes = require('./routes/category');
const orderRoutes = require('./routes/order');
const positionRoutes = require('./routes/position');
const keys = require('./config/keys');
const app = express();


mongoose.connect(keys.mongoURI, {
    useNewUrlParser: true, 
    useUnifiedTopology: true, 
    useCreateIndex: true
    })
    .then(() => console.log('MongoDB connected'))
    .catch(err => console.error(err));

app.use(passport.initialize());
require('./middleware/passport')(passport);
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cors());

app.use('/api/auth', authRoutes);
app.use('/api/analytics', analyticsRoutes);
app.use('/api/category', categoryRoutes);
app.use('/api/order', orderRoutes);
app.use('/api/position', positionRoutes);

module.exports = app;

/routes/auth.js:

const express = require('express');
const controller = require('../controllers/auth');
const router = express.Router();

router.post('/login', controller.login);
router.post('/register', controller.register);

module.exports = router;

/controllers/auth.js:

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User'); // модель пользователя
const keys = require('../config/keys');
const errorHandler = require('../utils/errorHandler');

module.exports.login = async function(req, res) {
    const candidate = await User.findOne({email: req.body.email});

    if (candidate) {
        // Проверка пароля, пользователь существует
        const passwordResult = bcrypt.compareSync(req.body.password, candidate.password);
        if (passwordResult) {
            // Генерация токена, пароли совпали
            const token = jwt.sign({
                email: candidate.email,
                userId: candidate._id
            }, keys.jwt, {expiresIn: 60 * 60});

            res.status(200).json({
                token: `Bearer ${token}`
            });
        } else {
            // Пароли не совпали
            res.status(401).json({
                message: 'Пароли не совпадают, пробуйте снова'
            });
        }
    } else {
        // Пользователя нет, ошибка
        res.status(404).json({
            message: 'Пользователь с таким Email не найден'
        })
    }
};

module.exports.register = async function(req, res) {
    const candidate = await User.findOne({email: req.body.email});
    if (candidate) {
        // Пользователь существует, нужно отдать ошибку
        res.status(409).json({
            message: 'Такой Email уже занят, попробуйте другой'
        });
    } else {
        // Нужно создать пользователя
        const salt = bcrypt.genSaltSync(10);
        const password = req.body.password
        const user = new User({
            email: req.body.email,
            password: bcrypt.hashSync(password, salt)
        });
        try {
            await user.save();
            res.status(201).json(user);
        } catch(e) {
            // Обработать ошибку
            errorHandler(res, e);
        }
        
    }
};

Использую приложение Postman для отправки http запросов на сервер.
Регистрирую пользователя, обращаясь к POST http://localhost:5000/api/auth/register

введите сюда описание изображения

Авторизуюсь, обращаясь к POST http://localhost:5000/api/auth/login, мне выдаётся токен

введите сюда описание изображения

Пытаюсь обратиться к GET http://localhost:5000/api/category, получить категории, отправляю ключ Authorization в Header, в который я ввёл токен, который мне выдался при регистрации, но получаю ответ Unathorized

введите сюда описание изображения

Роуты категорий: routes/category.js:

const express = require('express');
const passport = require('passport');
const upload = require('../middleware/upload');
const controller = require('../controllers/category');
const router = express.Router();

router.get('/', passport.authenticate('jwt', {session: false}), controller.getAll);
router.get('/:id', passport.authenticate('jwt', {session: false}), controller.getById);
router.delete('/:id', passport.authenticate('jwt', {session: false}), controller.remove);
router.post('/',  passport.authenticate('jwt', {session: false}), controller.create);
router.patch('/:id', passport.authenticate('jwt', {session: false}), upload.single('image'), controller.update);

module.exports = router;

/controllers/category.js, использую метод getAll, для получения всех записей:

const Category = require('../models/Category');
const Position = require('../models/Position');
const errorHandler = require('../utils/errorHandler');

module.exports.getAll = async function(req, res) {
    try {
        const categories = await new Category.find({user: req.user.id});
        res.status(200).json(categories);
    } catch(e) {
        errorHandler(res, e);
    }
};

middleware/passport.js:

const passportJwt = require('passport-jwt');
const JwtStrategy = passportJwt.Strategy;
const ExtractJwt = passportJwt.ExtractJwt;
const keys = require('../config/keys');
const mongoose = require('mongoose');
const User = mongoose.model('users');
const options = {
    jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken,
    secretOrKey: keys.jwt
};

module.exports = passport => {
    passport.use(
        new JwtStrategy(options, async (payload, done) => {
            try {
                const user = await User.findById(payload.userId).select('email id');

                if (user) {
                    done(null, user);
                } else {
                    done(null, false);
                }
            } catch(e) {
                console.error(e);
            }
        })
    )
};

Ответы (1 шт):

Автор решения: Михаил Камахин

Я забыл вызвать функцию ExtractJwt.fromAuthHeaderAsBearerToken

В файле /middleware/pasport.js объект options был такой:

const options = {
    jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken,
    secretOrKey: keys.jwt
};

А надо было:

const options = {
    jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
    secretOrKey: keys.jwt
};
→ Ссылка