I'm trying to add local authentication to my node.js app. After following the tutorial on: https://scotch.io/tutorials/easy-node-authentication-setup-and-local I have run into error: "TypeError: app.use() requires a middleware function".
I think this is related to the app.use(indexRoutes) in my app.js file but I'm not sure how to fix this? Any help would be greatly appreciated.
Here is my code so far:
app.js:
var express = require('express'),
session = require("express-session"),
bodyParser = require('body-parser'),
app = express().use(bodyParser.json()), //creates express http server
passport = require('passport'),
sanitizer = require('express-sanitizer'),
mongoose = require("mongoose"),
cookieParser = require('cookieparser'),
dotnev = require('dotenv').config(),
https = require('https'),
flash = require('connect-flash'),
fs = require('fs'),
config = require('./config/config'),
_ = require("underscore");
require('./config/passport')(passport);
var indexRoutes = require("./routes/index")(app, passport);
app.use(bodyParser.urlencoded({extended: true}));
app.use(sanitizer());
app.use(express.static(__dirname + "/public")); //tells express to serve the contents of the public directory
app.use(cookieParser);
//no longer need to specify that the view files are .ejs
app.set("view engine", "ejs");
app.use(session({
secret: "akjjkjnisaiuu8998323jdkadsih892rhoisdfasl",
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 1200000
}
}));
app.use(passport.initialize);
app.use(passport.session());
app.use(flash());
app.use(indexRoutes);
mongoose.connect(process.env.MONGOLAB_URL, { useNewUrlParser: true });
index.js:
var express = require("express"),
router = express.Router(),
_ = require("underscore"),
User = require("../models/user"),
auth = require("../routes/auth"),
config = require('../config/config'),
freshbooks = require("../modules/freshbooks"),
quickbooks = require("../modules/quickbooks");
module.exports = function(router, passport){
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
router.get("/register", auth.optional, function(req, res) {
res.render("register");
});
router.get("/login", auth.optional, function(req, res) {
res.render("login");
});
router.get("/admin", isLoggedIn, function(req, res) {
res.render('admin', {
user : req.user // get the user out of session and pass to template
});
});
//------------------------------------//
//***-------------AUTH-------------***//
//------------------------------------//
router.post('/register', passport.authenticate('local-signup', {
successRedirect : '/admin', // redirect to the secure profile section
failureRedirect : '/register', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
}
Thanks in advance for any help!
In app.js
var { registerIndexRoutes } = require("./routes/index");
var indexRoutes = registerIndexRoutes(router, passport);
app.use(indexRoutes);
and index.js
const registerIndexRoutes = function(router, passport){
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
return router;//important;
}
module.exports = { registerIndexRoutes };
It will help you.
You're getting that error because, this function, module.exports = function(router, passport){, is not a valid middleware.
From express docs: Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle.
The syntax goes:
function(req, res, next) {
// Implement the middleware function based on the options object
next()
}
req: HTTP response argument to the middleware function, called "res" by convention.
res: HTTP request argument to the middleware function, called "req" by convention.
next: Callback argument to the middleware function, called "next" by convention.
When you invoked this function, function(router, passport){:
var indexRoutes = require("./routes/index")(app, passport);
indexRoutes, contains the return value of function(router, passport) which does not return a middleware function (It returns undefined).
Two ways you can solve the issue:
Change your import:
// remove this line and put the below instead
app.use(cookieParser);
// and modify and move your import
require("./routes/index")(app, passport);
Use Express router: Change your index.js like
// note your exports it's not a function, you're exporting this **router** object -> router = express.Router(),
module.exports = router;
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
router.get("/register", auth.optional, function(req, res) {
res.render("register");
});
...
And change your import to:
var indexRoutes = require("./routes/index");
Related
I have an Express.js app with a Passport-local Auth, I'm tying to implement express router to my app since it's getting really hard to debug
This is an example of my main file (app.js)
const express = require('express')
const app = express()
const passport = require('passport')
const testing = require('./routes/file')
app.use(passport.initialize())
app.use(passport.session())
app.use('/router', testing)
const initializePassport = require('./passport-config');
initializePassport.initialize(passport);
app.get('/', checkAuthenticated, (req, res) => {
let user = data.key
res.send(`Hi ${user}`)
})
app.post('/login', checkNotAuthenticated, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}))
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect('/')
}
next()
}
app.listen(3000)
This is what my main file is like, this works perfectly fine
and just to make things clear, The function are to check if a user is authenticated or not, also my passport-config returns something called data.key which is basically the username of the user.
Now I've created a router here app.use('/router', testing) with the route as /router for testing purposes
Now this is my file.js that is being used by express
const express = require('express'), router = express.Router();
var bodyParser = require('body-parser');
// Handle POST requests
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
router.get('/test', checkAuthenticated, (req, res) => {
let user = data.key;
res.send(`Hello ${user}, this is coming from the router`)
})
module.exports = router;
Now as expected when I open the site at localhost:3000/router/test it returns a undefined error for data.key since it's not imported and then when I comment that out the line causing the error then checkAuthenticated doesn't work, even when I'm not logged in I can get access to the page, now this is the problem, how do I fix it, I've gone through the entire express router docs I couldn't find luck there.
Thanks
Your function is not in the global scope you need to set it to global to be able to see it like:
GLOBAL.authFunction = function(){
}
Suggestion:
1- make a module for auth name it authModule.
2- import the module auth check middleware where ever you want.
I am building a day planner, and while I was setting the routes I noticed I am receiving a 404 for every routes other than the main Home page route ie, index or "/".
This is app.js file
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var calendarRouter = require('./routes/calendar');
var app = express();
//Set up mongoose connection
var mongoose = require('mongoose');
var mongoDB = 'mongodb+srv://<user-name>:<password>#cluster0.3xw67.gcp.mongodb.net/<db-name>?retryWrites=true&w=majority';
mongoose.connect(mongoDB, { useNewUrlParser: true , useUnifiedTopology: true});
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/calendar', calendarRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
This is the calendar.js route
var express = require('express');
var router = express.Router();
var schedule_controller = require('../controllers/scheduleController');
router.get('/', schedule_controller.index);
router.get('/calendar/create', schedule_controller.schedule_create_get);
router.post('/calendar/create', schedule_controller.schedule_create_post);
router.get('/calendar/:id/delete', schedule_controller.schedule_delete_get);
router.post('/calendar/:id/delete', schedule_controller.schedule_delete_post);
router.get('/calendar/:id/update', schedule_controller.schedule_update_get);
router.post('/calendar/:id/update', schedule_controller.schedule_update_post);
router.get('/calendar/event/:id', schedule_controller.schedule_details);
router.get('/events', schedule_controller.schedule_list);
module.exports = router;
This is the index.js route, I did a redirect here!
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.redirect('/calendar');
});
module.exports = router;
And here is the Controller for the calendar.js route.
var Schedule = require('../models/schedule');
exports.index = function(req, res) {
res.send('NOT IMPLEMENTED: Site Home Page');
};
exports.schedule_list = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule List');
};
exports.schedule_details = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule Detail: ' + req.params.id);
};
exports.schedule_create_get = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule create GET');
};
exports.schedule_create_post = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule create POST');
};
exports.schedule_delete_get = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule delete GET');
};
exports.schedule_delete_post = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule delete POST');
};
exports.schedule_update_get = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule update GET');
};
exports.schedule_update_post = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule update POST');
};
Okay I found the bug it was me using index url that is / which I redirected to /calendar. And I have been using the rest of the url routes without calling the redirected one ie, /calendar.
I tried calling the routes with /calendar/calendar and it works!
I don't yet know clearly how to explain this. I hope fellow stackoverflow'ers could explain why this is happening.
Here's me trying a noob explanation!
Redirecting index route / to another url route, changes the main url route of the website(address). So all the sub routes which is everything other than the index route should explicitly call the redirected route (new address). Because every-time we call the old address the redirection changes it to the new one. Making the old address a dead one.
(Humour : I would like to point out an example considering numbers. It's like whole numbers and natural numbers. Redirection is when the whole number changes to natural number.)
I've looked through quite a bit of other posts and I'm very lost with this.
I can run a console.log(req) and get the following output
ServerResponse {
...
req:
IncomingMessage {
...
url: '/my-endpoint',
method: 'POST',
statusCode: null,
statusMessage: null,
...
body: { foo: 'bar' },
_body: true,
...
route: Route { path: '/my-endpoint', stack: [Object], methods: [Object] } },
...
Looks solid, so I would expect to do console.log(req.body) and get { foo: 'bar' } back in the console...but nope, getting undefined
After research, I found that it may be something with my app.js file and specifically with a body-parser, however, I have all of that already
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var http = require('http');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//Home Page Rendering
var index = require('./routes/index');
app.use('/', index);
// All other routes are kept in the `routes` module
require('./routes')(app);
module.exports = app;
routes.js
module.exports = function routing(app) {
var apiClient = require('./services/apiClient');
app.post('/get-device-info', function(err, req, res){
console.log("/get-device-info routes");
apiClient(req, res);
});
};
apiClient.js
module.exports = function callApi(req, res){
console.log(req);
console.log(req.body)
};
index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
Here's what I've tried
app.use(express.bodyParser());
Ensuring that the incoming request is explicitly declaring application/json
Declaring body parser.json in other ways
Adding a config function
Your problem is that Express doesn't use error first callbacks for its route handlers. The below code won't work because the app.post handler doesn't have the signature (req, res) => {}. In the below code err is equal to req, req is equal to res, and res is equal to next.
// routes.js
module.exports = function routing(app) {
var apiClient = require('./services/apiClient');
app.post('/get-device-info', function(err, req, res){
console.log("/get-device-info routes");
// Assuming the request is correct
// the value of body will be the request body
console.log(res.body)
apiClient(req, res);
});
};`
There are 3 different route callback signatures you can use in Express
(req, res) => {} - This is the most basic and defines a route that just cares about the request and response
(req, res, next) => {} - This is middleware callback signature which looks like a basic route callback but, it also assigns the next object which tells Express to call the next matching route.
(err, req, res, next) => {} - This is the error handling route callback and you only need 1 per Express Router Middleware or Express App. It gets called if next(err) is called within a Route or Middleware. More specifically, if next() isn't called with a string or nothing it will skip all remaining Middleware and Routes and go straight to the error handler. You can read more about it in the Express Docs
You'll need to change the route definition to
app.post('/get-device-info', (req, res) => {
apiClient(req, res)
})
Or you could even do this
module.exports = app => {
let apiClient = require('./services/apiClient')
app.post('/get-device-info', apiClient)
}
Try this, since it worked for me.
First declare app and then the bodyParser, since bodyParser is used within app:
const app = express();
const bodyParser = require('body-parser');
Then have these lines below:
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))
I'm quite new to Node.js and I'm trying to implement an authentication system through an external CAS server. I'm using Passport.js + passport-cas2 but it's always redirecting me to the failureRedirect page even though the CAS correctly authenticated me. Here is my code:
var SocketIOFileUpload = require('socketio-file-upload'),
socketio = require('socket.io'),
express = require('express'),
path = require('path'),
express = require('express'),
passport = require('passport'),
session = require('express-session'),
bodyParser = require('body-parser');
var CasStrategy = require('passport-cas2').Strategy;
var cas = new CasStrategy({
casURL: 'https://my.cas.server'
},
function(username, profile, done) {
console.log("authenticating");
done(null, new User());
});
var app = express()
.use(bodyParser.urlencoded({ extended: true }))
.use(SocketIOFileUpload.router)
.use(passport.initialize());
passport.use(cas);
app.use(session({ secret: 'my secret phrase' }))
.use(passport.session())
.get('/', function(req, res){
res.redirect('/auth/cas');
})
.get('/auth/cas',
passport.authenticate('cas', { failureRedirect: '/error', successRedirect: '/upload' }),
function(req, res) {
// Successful.
res.redirect('/upload');
})
.use('/upload', function(req, res, next){
if (req.user)
return express.static(path.join(__dirname, 'html'));
else
res.redirect('/auth/cas');
})
.get('/error', function(req, res) {
res.send('Error in authentication. Please Try Again.');
})
.listen(8080, function () {
console.log('Upload Server started on http://localhost:8080');
});
The console.log("authenticating") isn't even executed at all!
Thanks for your help.
Okay, I fixed it, my CAS server certificated was self-signed and I had to edit the passport-cas2 source in order for it to accept the certificate.
I'm trying to call the passport.authenticate function as response to post request for my registration view. I've been following this tutorial here to get my head around passport.js and express but having completed the first page of instructions and making the necessary changes for express.js 4.0 every page I try to access returns error 500 and displays the following stacktrace:
TypeError: Object #<serverResponse> has no method 'authenticate'
at module.exports (/home/myUserName/Desktop/manufacturing/routes/index.js:66:37)
at Layer.handle [as handle_request] (/home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/layer.js:82:5)
at trim_prefix (/home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/index.js:302:13)
at /home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/index.js:270:7
at Function.proto.process_params (/home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/index.js:321:12)
at next (/home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/index.js:261:10)
at /home/myUserName/Desktop/manufacturing/node_modules/connect-flash/lib/flash.js:21:5
at Layer.handle [as handle_request] (/home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/layer.js:82:5)
at trim_prefix (/home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/index.js:302:13)
at /home/myUserName/Desktop/manufacturing/node_modules/express/lib/router/index.js:270:7
Here is the code for /routes/index.js:
var express = require('express');
var bodyParser = require('body-parser');
var router = express.Router();
module.exports = function(app, passport) {
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', {
title: 'Home Page'
});
});
/* GET about page */
router.get('/about', function(req, res, next) {
res.render('about', {
title: 'About Us'
});
});
/* GET contact page */
router.get('/contact', function(req, res, next) {
res.render('contact', {
title: 'Contact Us'
});
});
/* GET login page */
router.get('/login', function(req, res, next) {
res.render('login', {
title: 'User Login',
message: req.flash('loginMessage')
});
});
/* GET register page */
router.get('/register', function(req, res, next) {
res.render('register', {
title: 'User Registration',
message: req.flash('signupMessage')
});
});
/* POST register page */
router.post('/register', passport.authenticate('local', {
successRedirect : '/',
failureRedirect : '/register',
failureFlash : true
}));
/* Log Out */
router.get('/logout', function(req, res, next) {
req.logout();
res.redirect('/');
});
/* 404 - page not found */
router.get('*', function(req, res){
res.render('404', {
title: '404 - Not Found'
});
});
// Route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
};
};
And here is my server.js:
var express = require('express');
var path = require('path');
var logger = require('morgan');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
var flash = require('connect-flash');
// Database
var configDB = require('./config/database.js');
mongoose.connect(configDB.url);
require('./config/passport')(passport);
// Routes
var routes = require('./routes/index');
var port = process.env.PORT || 3000;
var app = express();
// Express configuration
app.use(logger('dev')); // log every request to console
app.use(bodyParser.json()); // get information from html forms
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser()); // read cookies (needed for auth)
app.use(express.static(path.join(__dirname, 'public')));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
if (app.get('env') === 'development') {
app.locals.pretty = true;
}
// Passport configuration
app.use(session({ secret: 'MySecretHere',
saveUninitialized: true,
resave: true})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.use('/', routes);
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.listen(port);
console.log('Server running on ' + port);
The reason your are getting the error is because your exporting a function that takes app and passport as a parameters for your http handlers, but when your require it in your server.js your are not passing passport or app.
You need to somehow pass passport into the require.
You could change your routes files to
If your are using the express.Router
var router = express.Router();
module.exports = function(passport) {
// init your routes with passport and router
router.post('/' function(req, res) {
//...
});
// make sure to return router in the function though
return router;
}
If not using express.Router you could pass both app and passport and simply attach handlers to app
module.exports = function (app, passport) {
app.post('/', function(req, res) {
//...
});
// no need to return app
}
then in server.js
// if your using `express.Router()` in routes file
app.use('/', require('./routes')(passport));
// If your registering handler on app itself just bootstrap it
require('./routes')(app, passport);
You need to pass passport to your route. You can do it changing your code this way:
/routes/index.js
from module.exports = function(app, passport) {...}
to
module.exports = function(passport){ return function(app) {...}}
/server.js
from app.use('/', routes);
to app.use('/', routes(passport));