Mocking Auth Middleware Jest - javascript

hope you're doing well.
I have an endpoint I want to test that requires authentication using JWT (auth middleware). I tried to mock the function, but no result for now.
This is the route I want to test
router.post("", auth, async (req, res) => {
const newSkill = new Skill({
skill: req.body.skill,
position: req.body.position,
visibility: req.body.visibility,
icon: req.body.icon,
});
try {
await newSkill.save();
res.status(201).send(newSkill);
} catch (e) {
res.status(400).send();
}
});
This is my auth function:
const jwt = require("jsonwebtoken");
const Admin = require("../models/admin");
const auth = async (req, res, next) => {
try {
const token = req.header("Authorization").replace("Bearer ", "");
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const admin = await Admin.findOne({
_id: decoded._id,
"tokens.token": token,
});
if (!admin) {
throw new Error();
}
req.admin = admin;
next();
} catch (e) {
res.status(401).send({ error: "Please Authenticate." });
}
};
module.exports = auth;

Related

User is not authenticated jswtoken

I have created a login page and a about page the user will only access the about page if the user is logged in.
I am trying to authenticate the user by using the tokens generated while signing in, but the token is not getting authenticated even after signing in with the correct credentials. I don't know what is the problem?
This is code to my sign-in and token generating method
const express = require("express");
const { default: mongoose } = require("mongoose");
const router = express.Router();
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("../db/conn");
const User = require("../model/userSchema");
const cookieParser = require('cookie-parser');
const Authenticate = require("../middleware/authenticate");
router.use(cookieParser());
//LOgin route
router.post("/signin", (req, res)=>{
if(!req.body.email || !req.body.password){
return res.status(400).json({error: "Plz fill the required data"});
}else{
bcrypt.hash(req.body.password, 12, function (err, hash) {
User.findOne({email: req.body.email}, function (err, foundUser) {
if(err){
console.log(err);
}else{
if(foundUser){
bcrypt.compare(req.body.password, foundUser.password, function (err, result) {
if(result){
return res.json({message: "successfully log in"})
}else{
return res.json({message: "incorrect password"});
}
});
const email = req.body.email;
const token = jwt.sign(
{ user_id: foundUser._id, email },
process.env.TOKEN_KEY,
{
expiresIn: "720h",
}
);
foundUser.tokens = foundUser.tokens.concat({token: token});
foundUser.save();
// res.status(200).json(foundUser);
console.log(foundUser);
}else{
return res.status(400).json({message: "user not found"});
};
}
})
})
}
});
//about us page
router.get("/about", Authenticate, function (req, res) {
console.log("about running");
res.send(req.rootUser);
});
module.exports = router;
this is the code to authenticate the user
require("dotenv").config({path: "./config.env"});
const jwt = require("jsonwebtoken");
const User = require("../model/userSchema");
const Authenticate = async(req, res, next) =>{
try {
const token = req.cookies.jwtoken;
const verifyToken = jwt.verify(token, process.env.TOKEN_KEY);
const rootUser = await User.findOne({ _id: verifyToken._id, "tokens.token": token});
if(!rootUser) {
throw new Error("User not found")
}
req.token = token;
req.rootUser = rootUser;
req.userID = rootUser._id;
next();
} catch (err) {
console.log(err);
return res.status(401).send("Unauthorized: No token provided");
}
}
module.exports = Authenticate;
This is react based code of: About-page to display it or not based on user's authenticity.
const navigate = useNavigate();
const callAboutPage = async() =>{
try {
const res = await fetch("/about",{
method: "GET",
headers: {
Accept: "application/json",
"Content-Type" : "application/json"
},
credentials: "include"
});
const data = await res.json();
console.log(data);
if(!res.status === 200){
const error = new Error(res.error);
throw error;
}
} catch (err) {
console.log(err);
navigate("/login");
}
}
As said in the comment looks like there is a issue on the process for setting up the jwtoken, and when you sign in, you just need to find the user and compare the password, there is no need to do the hash with Bcrypt, since you're not registing new user, for example, i will use Async/await instead of callback function, in order for you to read it much more easier:
//Login route
router.post("/signin", async (req, res)=> {
const { reqEmail, reqPassword } = req.body; //destructuring so less thing to write at the next step
if(!reqEmail || !reqPassword) {
return res.status(400).json({message: "Plz fill the required data"});
}
try {
const foundUser = await User.findOne({email: reqEmail})
if(!foundUser) {
return res.status(400).json({message: "Wrong username or password!"})
}
const result = await bcrypt.compare(reqPassword, foundUser.password);
if(!result){
return res.json({message: "Wrong username or password!"})
} else {
const accessToken = jwt.sign(
{ user_id: foundUser._id, email: foundUser.email},
process.env.TOKEN_KEY,
{ expiresIn: "720h",}
);
// I am confuse what are you trying to do here, in your place I would set up on the cookie since you do that on your authentification.
res.cookie("jwt", accessToken, {
maxAge: 60000, // 60 sec for testing
httpOnly: true,
sameSite: false, //false only for dev
secure: false, //false only for dev
})
res.status(200).json(foundUser);
};
} catch (error) {
return res.status(500).json({message: `${error}`})
}
Than the authentification middleware :
// ...
const Authenticate = (req, res, next) => {
const accessToken = req.cookies.jwt
if(!accessToken) {
return res.status(401).json({error: "Unauthorized: No token provided"});
}
try {
const user = jwt.verify(accessToken, process.env.TOKEN_KEY)
if(user) {
req.user = user
return next();
}
} catch (error) {
return res.status(403).json({error: "Forbidden token error"})
}
}
about page component it's simple for now since you don't manage any state
const navigate = useNavigate();
const callAboutPage = async() =>{
try {
const res = await fetch("/about",{
headers: {
"Content-Type": "application/json"
},
credentials: "include"
});
if(res.status === 200){
const data = await res.json();
// set up the state for rendering
console.log(data);
} else {
// you can also create a state to catch the error message from the backend, in this case the response json should be move to above the if statement.
throw new Error("You must log in to get access")
// than you can display this error message, or from the backend using state for this bloc, and the catch bloc
// navigate to /login
}
} catch (err) {
console.log(err);
navigate("/login");
}
}
router.use(cookieParser());
Try to use cookieParser with app.use instead. (app from express instense)
Expample:
const app = express();
app.use(cookieParser());
and try to put it before server listening in index.js or app.js file.
Hope it help.

JWT Authorization is failing for all endpoints

So I am creating a social media application.
I used JWT token for verification on all endpoints. It's giving me custom error of "You are not authorized, Error 401"
For example: Create post is not working:
This is my code for JWT
const jwt = require("jsonwebtoken")
const { createError } = require ("../utils/error.js")
const verifyToken = (req, res,next) => {
const token = req.cookies.access_token
if(!token) {
return next(createError(401,"You are not authenticated!"))
}
jwt.verify(token, process.env.JWT_SECRET, (err,user) => {
if(err) return next(createError(401,"Token is not valid!"))
req.user = user
next()
}
)
}
const verifyUser = (req, res, next) => {
verifyToken(req,res, () => {
if(req.user.id === req.params.id || req.user.isAdmin) {
next()
} else {
return next(createError(402,"You are not authorized!"))
}
})
}
const verifyAdmin = (req, res, next) => {
verifyToken(req, res, next, () => {
if (req.user.isAdmin) {
next();
} else {
return next(createError(403, "You are not authorized!"));
}
});
};
module.exports = {verifyToken, verifyUser, verifyAdmin}
This is my createPost API:
const createPost = async (req, res) => {
const newPost = new Post(req.body);
try {
const savedPost = await newPost.save();
res.status(200).json(savedPost);
} catch (err) {
res.status(500).json(err);
}
}
Now, in my routes files, I have attached these functions with every endpoints.
For example: In my post.js (route file)
//create a post
router.post("/", verifyUser, createPost);
When I try to access it, this is the result
But, when I remove this verify User function from my route file, it works okay.
I have tried to re-login (to generate new cookie) and then try to do this but its still giving me error.
What can be the reason?
P.S: my api/index.js file https://codepaste.xyz/posts/JNhIr9W6zNnN26CH9xWT
After debugging, I found out that req.params.id is undefined in posts routes.
It seems to work for user endpoints since it contains req.params.id
const verifyUser = (req, res, next) => {
verifyToken(req,res, () => {
if(req.user.id === req.params.id || req.user.isAdmin) {
next()
} else {
return next(createError(402,"You are not authorized!"))
}
})
}
So I just replaced === with || and its working. (but its not right)
if(req.user.id || req.params.id || req.user.isAdmin) {
Can anyone tell me the how can I truly apply validation here since in my posts routes i dont have user id in params

axios get req error can not access http only token in next js but workd fine in post main

hy am building an forum in next js using httponly cookie for jwt authantication but get this error
this is my auth middleware
import jwt from "jsonwebtoken";
import createError from "http-errors";
import Cookies from "cookies";
/**
* #param {import('next').NextApiRequest} req
* #param {import('next').NextApiResponse} res
*/
module.exports = (req, res, next) => {
const cookies = new Cookies(req, res);
const token = cookies.get("token");
console.log(token);
// const { cookies } = req;
// const token = cookies.token;
if (!token) return next(createError("Unauthorized"));
try {
const user = jwt.verify(token, process.env.NEXT_PUBLIC_JWT);
req.user = user;
console.log(req.user);
next();
} catch (error) {
return next(createError("Login to gain access "));
}
};
this my api to get questions posted by user
import nextConnect from "next-connect";
import connect from "../../../utils/connectMongo";
import Question from "../../../models/question";
import auth from "../../../middleware/auth";
import Cookies from "cookies";
/**
* #param {import('next').NextApiRequest} req
* #param {import('next').NextApiResponse} res
*/
connect();
const apiRoute = nextConnect({
onError(error, req, res) {
res.status(501).json({ error: ` ${error.message}` });
console.log(error);
},
onNoMatch(req, res) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
apiRoute.use(auth);
apiRoute.get(async (req, res, next) => {
console.log(req.cookies);
try {
const { _id } = req.user;
console.log(req.user);
let { page, size } = req.query;
const limit = parseInt(size);
const skip = (page - 1) * size;
const question = await Question.find({ user: _id })
.limit(limit)
.skip(skip)
.populate("user", "name picture")
.sort({ createdAt: -1 });
res.status(200).json({
success: true,
data: question,
});
} catch (error) {
console.log(error);
res.status(400).json({ success: false });
}
});
// export const config = {
// api: {
// bodyParser: false, // Disallow body parsing, consume as stream
// },
// };
export default apiRoute;
in postman api works fine but in axios it says Unauthorized form auth middleware
my axios configs are
this is how i made req to server
export async function getStaticProps(page, size) {
const response = await instance.get(
`${baseUrl}/api/question/userquestion`,
{ withCredentials: true }
);
const questions = await response.data.data;
return {
props: {
questions,
},
};
}
enter image description here

JWT token invalid, but why

I'm doing one of my first exercises on authorization, but I can't understand what I'm doing wrong with this one. I'm trying to validate the JWT token, but it gives me back that it's invalid
I get the token with httpie:
http POST :4000/auth/login email=test#test.com password=test
And then I try validating with httpie:
http GET :4000/images authorization:"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTY0ODgyMDI3MCwiZXhwIjoxNjQ4ODI3NDcwfQ.AhArOvQTaJ7ohbPiyGiGTK5pFMWqjbZ5Kj9q2hXEhXU"
Which gives me: Invalid JWT token
This is my router/images.js
const { Router } = require("express");
const Image = require("../models").image;
const router = new Router();
const toData = require("../auth/jwt");
router.get("/images", async (req, res) => {
const auth =
req.headers.authorization && req.headers.authorization.split(" ");
if (auth && auth[0] === "Bearer" && auth[1]) {
try {
const data = toData(auth[1]);
const allImages = await Image.findAll();
res.send(allImages);
} catch (error) {
res.status(400).send("Invalid JWT token");
}
} else {
res.status(401).send({ message: "Please supply valid credentials" });
}
});
This is the router/auth.js
const { Router } = require("express");
const { toJWT, toData } = require("../auth/jwt");
const router = new Router();
router.post("/auth/login", async (req, res, next) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).send("Email and password required");
} else {
res.send({ jwt: toJWT({ userId: 1 }) });
}
} catch (error) {
console.log(error.message);
next(error);
}
});
module.exports = router;
This is the auth/jwt.js
const jwt = require("jsonwebtoken");
const secret =
process.env.JWT_SECRET || "e9rp^&^*&#9sejg)DSUA)jpfds8394jdsfn,m";
const toJWT = (data) => {
return jwt.sign(data, secret, { expiresIn: "2h" });
};
const toData = (token) => {
return jwt.verify(token, secret);
};
module.exports = { toJWT, toData };
Hope somebody can help :)
Inside your router/images.js file, it looks like you are not requiring the toData method correctly. You are requiring the module with two exported functions, so if you use destructuruing, you would have to access your toData method like you did inside of auth.js.
Change line 4 of router/images.js to:
const { toData } = require("../auth/jwt");
When you require the auth/jwt file with a single const that is not destructured, you would access the exported methods of that file with dot notation:
const jwt = require("../auth/jwt");
jwt.toData(auth[0]);

front end react is not sending data to to mongoDB database

THE app is suppose to register the new user and send the new users info to the MongoDB, but when i attempt to register the user it throws an error of 500 internal error. the console says the error is in the user file, the terminal say this is the error, Proxy error: Could not proxy request /api/users from localhost:3000 to https://localhost:5000.
[1] See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (EPROTO).
I've already tried changing the proxy in the packet.json by giving it a different path and target but its not working. maybe i'm overlooking something. enter code here
import React, { useReducer } from 'react';
import axios from 'axios';
import AuthContext from './authContext';
import authReducer from './authReducer';
import {
REGISTER_SUCCESS,
REGISTER_FAIL,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
CLEAR_ERRORS
} from '../types';
const AuthState = props => {
//initial state
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
user: null,
loading: true,
error: null
};
const [ state, dispatch ] = useReducer(authReducer, initialState);
// load user
const loadUser = () => console.log('load user') ;
// register user
const register = async formData => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
try {
const res = await axios.post('api/users', formData, config);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
});
} catch (err){
dispatch({
type: REGISTER_FAIL,
payload: err.response.data.msg
});
}
}
// login user
const login = () => console.log('login') ;
//logut
const logout = () => console.log('logout') ;
// clear errors
const clearErrors = () => console.log('clearErrors') ;
return (
<AuthContext.Provider
value= {{
token: state.token,
isAuthenticated: state.isAuthenticated,
loading: state.loading,
user: state.user,
error: state.error,
register,
loadUser,
login,
logout,
clearErrors
}}>
{props.children}
</AuthContext.Provider>
);
};
export default AuthState;
//this is my server.js file with the routes
const express = require('express');
const connectDB = require('./config/db')
//connect MongoDB
connectDB();
const app = express();
//init middleware
app.use(express.json({extended: false}));
app.get('/', (req, res) => res.json({ msg: 'hello welcome'})
);
//define routes
app.use('/api/users', require('./routes/users'));
app.use('/api/auth', require('./routes/auth'));
app.use('/api/contacts', require('./routes/contacts'))
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server is working on ${PORT}`))
// this is mongoDB code
const mongoose = require('mongoose');
const config = require('config');
const db = config.get('mongoURI');
const connectDB = async () =>{
try{ await
mongoose.connect(db, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false
});
console.log('mongo connected..')
} catch (err){
console.log(err.message);
process.exit(1)
}
};
module.exports = connectDB;
// this the users file where the console is throwing the 500 internal error.
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../models/User')
// This route Post request to api/users,
// description register a user,
// access to public to register an become a user
router.post('/', [
check('name', 'Name is require').not().isEmpty(),
check('email', 'please include email').isEmail(),
check('password', 'enter a password with atleast 6 characters'
).isLength({min: 6})
],
async (req, res) =>{
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors: errors.array()});
}
const { name, email, password } = req.body;
try{
let user = await User.findOne({email});
if(user){
return res.status(400).json({msg: 'user already exist'})
}
user = new User({
name,
email,
password
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
// object to send in the token
const payload = {
user: {
id: user.id
}
}
jwt.sign(payload, config.get('jwtSecret'), {
expiresIn: 36000
}, (err, token) => {
if(err) throw err;
res.json({token});
});
} catch (err){
console.log(err.message);
res.status(500).send('server error')
}
});
module.exports = router;
I figure out the problem!!!
I had an unexpected token in my users file that simple colon was interfering with the code

Categories

Resources