Home > Enterprise >  JWT secret and algorithm are both set when user creates account yet i got this algorithm problem
JWT secret and algorithm are both set when user creates account yet i got this algorithm problem

Time:10-09

i have been stuck for 3 days straight the error that i'm getting

if (!options.algorithms) throw new Error('algorithms should be set');

but why would i pass option algorithm when i already signed my token to with it's algorithm is there anyway to solve this problem appreciate your help

this is my authController!

const jwtDecode = require('jwt-decode');
const User = require('../models/userModel');
const jwt = require('express-jwt');
const dotenv = require('dotenv');

dotenv.config({ path: '.env' });

const { createToken, hashPassword, verifyPassword } = require('../utils/apiToken');

exports.authenticate =  async (req, res) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email }).lean();
    if (!user) {
      return res.status(403).json({
        message: 'Wrong email or password.'
      });
    }
    const passwordValid = await verifyPassword(password, user.password);
    if (passwordValid) {
      const { password, bio, ...rest } = user;
      const userInfo = Object.assign({}, { ...rest });
      const token = createToken(userInfo);
      const decodedToken = jwtDecode(token);
      const expiresAt = decodedToken.exp;
      res.status(201).json({
        message: 'Authentication successfull!',
        token,
        userInfo,
        expiresAt
      });
    } else {
      res.status(403).json({
        message: 'Wrong email or password.'
      });
    }
  } catch (err) {
    console.log(err);
    return res.status(400).json({ message: 'Something Went totally wrong.' });
  }
};

exports.signup = async (req, res) => {
  try {
    const { email, firstName, lastName, role } = req.body;
    const hashedPassword = await hashPassword(req.body.password);

    const userData = {
      email: email.toLowerCase(),
      firstName,
      lastName,
      password: hashedPassword,
      role: role
    };
    const existingEmail = await User.findOne({ email: userData.email }).lean();
    if (existingEmail) {
      return res.status(400).json({ message: 'Email already exists' });
    }

    const newUser = new User(userData);
    const savedUser = await newUser.save();

    if (savedUser) {
      const token = createToken(savedUser);
      const decodedToken = jwtDecode(token);
      const expiresAt = decodedToken.exp;
      //FirstName,lastName,Email,Role = savedUser;

      const userInfo = {
        firstName,
        lastName,
        email,
        role
      };

      return res.status(201).json({
        message: 'User created!',
        token,
        userInfo,
        expiresAt
      });
    } else {
      return res.status(400).json({
        message: 'There was a problem creating your account'
      });
    }
  } catch (err) {
    return res.status(400).json({
      message: 'There was a problem creating your account',
      error: err.message
    });
  }
};

this is my util functionality

const jwt = require('jsonwebtoken');
const jwtE = require('express-jwt');
const bcrypt = require('bcryptjs');
const dotenv= require('dotenv')
dotenv.config({ path: '.env' });


const createToken = user => {
  // Sign the JWT
  if (!user.role) {
    throw new Error('No user role specified');
  }
  return jwt.sign({
      sub: user._id,
      email: user.email,
      role: user.role,
      iss: 'api.orbit',
      aud: 'api.orbit'
    },
    process.env.JWT_SECRET,
    { algorithm: 'HS256', expiresIn: '1h' }
  );
};

const hashPassword = password => {
  return new Promise((resolve, reject) => {
    bcrypt.genSalt(12, (err, salt) => {
      if (err) {
        reject(err);
      }
      bcrypt.hash(password, salt, (err, hash) => {
        if (err) {
          reject(err);
        }
        resolve(hash);
      });
    });
  });
};

const verifyPassword = (passwordAttempt, hashedPassword) => {
  return bcrypt.compare(passwordAttempt, hashedPassword);
};

const requireAdmin = (req, res, next) => {
  if (!req.user) {
    return res.status(401).json({
      message: 'There was a problem authorizing the request'
    });
  }
  if (req.user.role !== 'admin') {
    return res.status(401).json({ message: 'Insufficient role' });
  }
  next();
};

const attachUser = (req, res, next) => {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).json({ message: 'Authentication invalid' });
  }

  const decodedToken = jwtDecode(token.slice(7));
  if (!decodedToken) {
    return res.status(401).json({
      message: 'There was a problem authorizing the request'
    });
  } else {
    req.user = decodedToken;
    next();
  }
};

const requireAuth = jwtE({
  secret: process.env.JWT_SECRET,
  audience: 'api.orbit',
  issuer: 'api.orbit'
});

module.exports = {
  createToken,
  hashPassword,
  verifyPassword,
  requireAdmin,
  attachUser,
  requireAuth
};

this is my route

const express = require('express');
const userController = require('./../controllers/userController');
const authController = require('./../controllers/authController');
const router = express.Router();
const { attachUser, requireAuth } = require('../utils');

//Param middle is middleware that runs for certain param
//the only param that we have id
// router.param('id', (req, res, next, val) => {
//    console.log(`product id is :${id}`)
//    next()
// })

router.post('/signup', authController.signup);
router.post('/authenticate', authController.authenticate);

router.route('/')
   .get(attachUser, requireAuth, userController.getAllUsers)
   .post(attachUser, requireAuth, userController.createUser);

router.route('/:id')
   .get(attachUser, requireAuth, userController.getUser)
   .patch(attachUser, requireAuth, userController.updateUser)
   .delete(attachUser, requireAuth, userController.deleteUser);

module.exports = router;

CodePudding user response:

First, you have to Generate a JWT token when the user successfully logged in...

exports.login = async (req, res, next) => {
  const email = req.body.email;
  const password = req.body.password;
  let loadedUser;
  try {
    const user = await User.findOne({ email: email });
    if (!user) {
      const error = new Error("A user with this email could not be found.");
      error.statusCode = 401;
      throw error;
    }
    loadedUser = user;
    const isEqual = await bcrypt.compare(password, user.password);
    if (!isEqual) {
      const error = new Error("Wrong password!");
      error.statusCode = 401;
      throw error;
    }
    const token = jwt.sign(
      {
        email: loadedUser.email,
        userId: loadedUser._id.toString(),
      },
      "somesupersecretsecret",
      { expiresIn: "1h" }
    );
    res.status(200).json({ token: token, userId: loadedUser._id.toString() });
  } catch (err) {
    if (!err.statusCode) {
      err.statusCode = 500;
    }
    next(err);
  }
};

After that, you have to create an Auth Middleware

const jwt = require('jsonwebtoken');

module.exports = (req, res, next) => {
  const authHeader = req.get('Authorization');
  if (!authHeader) {
    const error = new Error('Not authenticated.');
    error.statusCode = 401;
    throw error;
  }
  const token = authHeader.split(' ')[1];
  let decodedToken;
  try {
    decodedToken = jwt.verify(token, 'somesupersecretsecret');
  } catch (err) {
    err.statusCode = 500;
    throw err;
  }
  if (!decodedToken) {
    const error = new Error('Not authenticated.');
    error.statusCode = 401;
    throw error;
  }
  req.userId = decodedToken.userId;
  next();
};

After that, you can easily import this middleware and routes and use it for great User auth.

  • Related