I create user service with login and register in node js. when i using authenticate middleware i got this kind of errors. if any one have solution. please let me know. i attached code and error image.
this is my route file.
const { Router} = require('express');
const authController = require('../controllers/authController');
const {authMiddleware} = require('../middleware/authMiddleware')
const router = Router();
router.get('/users',{authMiddleware}, authController.users_get);
router.post('/users',authController.users_post);
router.post('/authenticate',authController.authenticate_post);
module.exports = router;
this is my middleware file
const jwt = require('jsonwebtoken');
const requireAuth =(req, res, next)=>{
const token = req.cookie.jwt;
//check json web token exists & is verified
if(token){
jwt.verify(token,'vivekeviv',(err, decodedToken)=>{
if (err){
console.log(err)
}
else {
console.log(decodedToken);
next();
}
})
}
else {
console.log("You need to login")
}
}
module.exports ={requireAuth}
how to add middleware to this code.
i got this kind of error.
You are passing an object where express is expecting a function. You want:
const {requireAuth} = require('../middleware/authMiddleware')
...
router.get('/users', requireAuth, authController.users_get);
Related
I'm writing Rest API in Node.JS which use MySQL database but also external API, where I need fetch some data.
I'm using Express and "Router, Middleware, Controller, Model" Architecture and I'n not sure what is the right solution to call an external API. In every request I'm sending token that is required for external API. I show what I have now and try describe the problem what I currently have (Read comments in code please.)
(Also if you have some articles or tutorials where is describe how right write Rest API in node thats uses Router, Middleware, Controller, Model architecture please let me know)
This is the main index.js
const express = require("express");
const dotenv = require('dotenv');
const cors = require("cors");
const HttpException = require('./utils/HttpException.utils');
const errorMiddleware = require('./middleware/error.middleware');
const userRouter = require('./routes/user.route');
const axios = require("axios");
// Init express
const app = express();
// Init environment
dotenv.config();
// parse requests of content-type: application/json
// parses incoming requests with JSON payloads
app.use(express.json());
// enabling cors for all requests by using cors middleware
app.use(cors());
// Enable pre-flight
app.options("*", cors());
const port = Number(process.env.PORT || 3331);
app.use(`/api/v1/users`, userRouter);
// This is an solution that works but I thinks is and nasty way how to do it
// You can see here how I need to call external API
app.get('/api/v1/test', (req, res, next) => {
const token = req.headers.token;
const respond = await axios.get(EXTERNAL_API_ENDPOINT, {
headers: {
cookie: `token=${token}`
}
});
});
// 404 error
app.all('*', (req, res, next) => {
const err = new HttpException(404, 'Endpoint Not Found');
next(err);
});
// Error middleware
app.use(errorMiddleware);
// starting the server
app.listen(port, () =>
console.log(`Server running on port ${port}!`));
module.exports = app;
user.route.js
const express = require('express');
const router = express.Router();
const userModel = require('../models/user.model');
const awaitHandlerFactory = require('../middleware/awaitHandlerFactory.middleware');
router.get('/currentUser', awaitHandlerFactory(userModel.getCurrentUser));
router.get('/logout');
module.exports = router;
I also have an Auth middleware to check token validation where i need to call external API which validate user.
Auth.middleware.js
const HttpException = require('../utils/HttpException.utils');
const UserModel = require('../models/user.model');
const dotenv = require('dotenv');
dotenv.config();
const auth = (roles) => {
return async function (req, res, next) {
try {
const token = req.headers.token;
if (!token) {
throw new HttpException(401, 'Access denied. No credentials sent!');
}
/* here I need call the external API and think that I should call it from
UserModal?, but I can't because Modal doesn't have req (should I sent it
in function parmas? like this?)*/
const user = await UserModel.getCurrentUser(token, params);
if (!user) {
throw new HttpException(401, 'Authentication failed!');
}
if(!user.active || user.active !== 'Y'){
throw new HttpException(401, `User ${user.userName} is not active!`);
}
// if the user role don't have the permission to do this action.
// the user will get this error
if (roles.length && !roles.includes(user.role)) {
throw new HttpException(401, 'Unauthorized');
}
// if the user has permissions
req.currentUser = user;
next();
} catch (e) {
e.status = 401;
next(e);
}
}
}
module.exports = auth;
I`m not sure how to handle this. I have to provide token and some data to call external API. Im not sure, if I shloud call Model or do it by Controller (or middleware?).
Where and how I should do it and why? Thanks!
Looks alright to me. Really depends on whether or not the API call needs to be made every request. Let say the user makes a request to your API, which then makes a request to an external API to authenticate that user, you're gonna need the auth token from every request.
You can organize your code a little better though. As example:
📦api
┣ 📂controllers
┃ ┗ 📜test.js
┣ 📂services
┃ ┗ 📜EXTERNAL_API_ENDPOINT.js
┗ 📜index.js
api/services/EXTERNAL_API_ENDPOINT.js
const axios = require("axios");
async function getService(token) {
return axios.get(EXTERNAL_API_ENDPOINT, {
headers: { cookie: `token=${token}` }
});
}
module.exports = getService;
api/controllers/test.js
const getService = require("../services/EXTERNAL_API_ENDPOINT");
async function test(req, res, next) {
const token = req.headers.token;
const respond = await getService(token)
}
module.exports = test;
api/index.js
const test = require("./controllers/test");
app.get('/api/v1/test', test);
I get error which is cannot access to passport before intializing.
how can i fix it and access to passport through the the route.
and i defined passport in the app.js file and it's middleware
const passport = require(passport) ;
const intializePassport = require("../passportConfig");
const { check,validationResult } = require('express-validator');
const flash = require('express-flash');
const {Router}=require('express');
const authController = require('../controllers/authControllers')
const router = Router()
router.get('/signup',authController.signup_get) ;
router.post('/signup',authController.signup_post);
router.get('/login',authController.login_get);
router.post('/login',passport.authenticate("local",{
successRedirect : "/dashboard",
failureRedirect:"/login",
failureFlash:true ,
})
);
function checkAuthenticated(req,res,next){
if (req.isAuthenticated()){
return res.redirect('/dashboard');
}
next()
}
function checkNotAuthenticated(req,res,next){
if (req.isAuthenticated()){
return next();
}
res.redirect('/login')
}
module.exports=router;
You need to initialize passport before using it, the error is fairly straightforward. If you are still getting error then kindly share your app.js as well. Anyways, just do this:
const intializePassport = require("../passportConfig"); // First
const passport = require(passport); // Second
I have making an API using express and node.
Here is my app.js
const express = require('express');
const bodyParser = require('body-parser');
const dotenv = require('dotenv');
// setup dotenv to read environment variables
dotenv.config()
// Load Environment Varibles
const env = require('./utils/env');
// INIT MONGODB CONNECTION
require('./mongoose');
// create a new express application
const app = express();
// setup bodyparser middleware to read request body in requests
// we're only reading JSON inputs
app.use(bodyParser.json());
// Listen to API routes
const apiRoutes = require('./routes')
app.use('/api', apiRoutes);
// Start listening to requests
app.listen(env.PORT, () => {
console.log(`Server started on PORT ${env.PORT}`);
});
And here is the API routes that are being imported
const express = require('express');
const apiController = require('./apiController');
const apiValidator = require('./apiValidator');
const router = express.Router();
router.post('/login', apiValidator.loginUserValidator, apiController.loginUserController);
router.get('/rand', (req, res) => {
res.send('Some randon text');
});
module.exports = router;
Here is the middleware
const {
failureResponse
} = require('./../utils/response');
const errorcodes = require('./../utils/errorcodes');
const loginUserValidator = (req, res, next) => {
const user = req.body;
if (!user.username) {
return res.status(400).json(failureResponse(errorcodes.ERROR_INVALID_BODY_PARAMETER, "Invalid username"));
}
if (!user.password) {
return res.status(400).json(failureResponse(errorcodes.ERROR_INVALID_BODY_PARAMETER, "Invalid password"));
}
if (user.authTokens) {
delete user.authTokens;
}
next();
};
module.exports = {
loginUserValidator
};
Here is the controller
const User = require('./../models/user');
const {
successResponse,
failureResponse
} = require('./../utils/response');
const errorcodes = require('./../utils/errorcodes');
const loginUserController = async (req, res) => {
try {
const user = req.body;
// find if the user already exists
const existingUser = await User.findOne({
username: user.username
});
if (existingUser) {
// user exists. generate token and login user
console.log('Existing user login');
const token = existingUser.generateAuthToken();
return res.status(200).json(successResponse(token));
} else {
console.log('New user login');
const savedUser = await new User(user).save();
const token = savedUser.generateAuthToken();
return res.status(200).json(successResponse(token));
}
} catch (e) {
console.log(e);
return res.status(400).json(failureResponse(errorcodes.ERROR_SERVER_ERROR, "Unable to login user"));
}
};
module.exports = {
loginUserController
};
Here the issue is when I try to hit the login route from Postman, I am getting an error which says Could not get any response.
But when I hit the rand route, the output is correct.
So the issue isn't the arrangement of the code.
Why am I not able to use the login route here?
i'm a beginner in node.js and trying to redirect a post request. here is the code snippet
const mongoose = require('mongoose');
const passport = require('passport');
const router = require('express').Router();
const auth = require('../auth');
const Users = mongoose.model('Users');
router.post('/createuser', auth.required, (req, res, next) => {
const { payload: { id } } = req;
//var id = req.get("authorization");
console.log("in create User route");
return Users.findById(id)
.then((user) => {
if(!user) {
return res.sendStatus(400);
}
//res.send(req.body);
res.redirect(307,'http://localhost:8181/user');
});
});
I hit the URL from Advance Rest Client and get this statement
"Temporary Redirect. Redirecting to http://localhost:8181/user"
but there is no redirection. i also tried
res.redirect(302,'http://localhost:8181/user');
and
res.redirect('http://localhost:8181/user');
but it doesn't work.
I did not tried this using express. But below code works in node.
res.writeHead(302,{'Location':'url/test'});
res.end();
Just do res.redirect('/myroutes'); You don't need to declare your host as well.
For example, in Meteor, there's something like
Router.plugin('ensureSignedIn');
Router.plugin('ensureSignedIn', {
except: ['home', 'atSignIn', 'atSignUp', 'atForgotPassword']
});
So unsigned user cannot access other routes except above four.
How to do this in express.js? I'm using passport.js also.
I'm not familiar with Meteor, but you can do something like the following, assuming you want to make pages available to only authenticated users (passport).
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated())
return next();
else
// Return error content: res.jsonp(...) or redirect: res.redirect('/login')
}
app.get('/account', ensureAuthenticated, function(req, res) {
// Do something with user via req.user
});
The ensureAuthenticated function is just an example, you can define your own function. Calling next() continues the request chain.
I should use middleware for protect my routes, even to protect certain verbs in the same route:
for example: in my endpoint/route.js
// the require sentences are omitted
const express = require('express');
const { /*controllerFunctions*/ } = require('./controller');
const {routeGuard} = require('/*must create a route guard*/');
const router = express.Router();
router.route('')
.get(getAllResources)
;
router.route('/:id') //
.get(validateParam,getOneResource);
router.use(routeGuard);
router.route('/:id')
.post(validateParam,validateBody,postResource)
.patch(validateParam,validateBody,patchProblemById)
.delete(validateParam,deleteResource)
;
module.exports = router;
and my routeGuard file should be like this:
const { promisify } = require('util');
const jwt = require("jsonwebtoken");
const AppError = require('./appError');
const {User} = require('./../endpoints/users/model');
const wrapper = require('./try-wrapper');//try catch wrapper
module.exports.routeGuard = wrapper(async function (req, res, next){
// the err message is the same on purpose
const notAllowed = new AppError('Unauthorized: Invalid or Nonexistent credentials',401);
let token = null;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')){
token = req.headers.authorization.split(' ')[1];
}
if (!token) return next(notAllowed );
const payload = await promisify(jwt.verify)(token,process.env.KEY);
const user = await User.findById(payload.id);
if (!user) return next( notAllowed);
if ( ! user.hasSamePasswordSince(payload.iat) )return next( notAllowed );
req.user = user; // further use...
next();
});