I am new to Javascript and even newer to Node. I am trying to read an express server code and can't figure out following line in my app.js file:
module.require('./auth')(passport);
I know I have a variable that holds passport module in app.js:
var passport = require('passport');
and I also have auth.js in the same directory which exports the following function:
module.exports = function(passport) {
passport.use('local-login', new LocalStrategy({
usernameField: 'email'
}, function(idpEmail, password, done) {
// do email mapping
findEmailFromDummyDb(idpEmail, password,function(err,user){
if(err) {
done(null, false, {
messages: err.toString()
});
} else {
done(null, {
sysEmail: user.sysEmail
});
}
});
}));
However, what does following function actually do?
module.require('./auth')(passport);
module.require('./auth') imports a function, then it get's called with passport as a parameter. It's the same as
const auth = require('./auth');
const passport = require('passport');
auth = auth(passport);
The below returns a javascript function.
module.require('./auth');
You are then immediately calling the function with the passport object as a function argument.
(passport)
Related
Using passport.js local strategy I am trying to use the req.user to obtain current user id so that I can store recipes in the database with the users id. The problem seems to be around the deserialization part of the passport.js file I have in my config file in my app. Whenever I hit the /api/saveRecipe route for some reason it gets deserialized and the req user is then no longer available.
Notes: I am authenticating on my backend server using react on the front end.
Below is my server.js file
Problem: req.user is available after calling passport.authenticate('local') but once api/saveRecipe route is hit req.user is no longer available.
After researching this subject on S.O. it appears that it most often has to do with order in the server file setup but i have looked and reviewed and i believe my setup correct...
const express = require("express");
const bodyParser = require("body-parser");
const session = require("express-session");
const routes = require("./routes");
// Requiring passport as we've configured it
let passport = require("./config/passport");
const sequelize = require("sequelize");
// const routes = require("./routes");
const app = express();
var db = require("./models");
const PORT = process.env.PORT || 3001;
// Define middleware here
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
// passport stuff
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static("public"));
// We need to use sessions to keep track of our user's login status
// app.use(cookieParser('cookit'));
app.use(
session({
secret: "cookit",
name: "cookit_Cookie"
})
);
app.use(passport.initialize());
app.use(passport.session());
// Serve up static assets (usually on heroku)
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/public"));
}
// the view files are JavaScript files, hence the extension
app.set('view engine', 'js');
// the directory containing the view files
app.set('pages', './');
// Add routes, both API and view
app.use(routes);
// Syncing our database and logging a message to the user upon success
db.connection.sync().then(function() {
console.log("\nDB connected\n")
// Start the API server
app.listen(PORT, function() {
console.log(`🌎 ==> API Server now listening on PORT ${PORT}!`);
});
});
module.exports = app;
my passport.js code
//we import passport packages required for authentication
var passport = require("passport");
var LocalStrategy = require("passport-local").Strategy;
//
//We will need the models folder to check passport against
var db = require("../models");
// Telling passport we want to use a Local Strategy. In other words, we want login with a username/email and password
passport.use(
new LocalStrategy(
// Our user will sign in using an email, rather than a "username"
{
usernameField: "email",
passwordField: "password",
passReqToCallback: true
},
function(req, username, password, done) {
// console.log(`loggin in with email: ${username} \n and password: ${password}`)
// When a user tries to sign in this code runs
db.User.findOne({
where: {
email: username
}
}).then(function(dbUser) {
// console.log(dbUser)
// If there's no user with the given email
if (!dbUser) {
return done(null, false, {
message: "Incorrect email."
});
}
// If there is a user with the given email, but the password the user gives us is incorrect
else if (!dbUser.validPassword(password)) {
return done(null, false, {
message: "Incorrect password."
});
}
// If none of the above, return the user
return done(null, dbUser);
});
}
)
);
// serialize determines what to store in the session data so we are storing email, ID and firstName
passport.serializeUser(function(user, done) {
console.log(`\n\n serializing ${user.id}\n`)
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log(`\n\n DEserializing ${id}\n`)
db.User.findOne({where: {id:id}}, function(err, user) {
done(err, user);
});
});
// Exporting our configured passport
module.exports = passport;
const router = require("express").Router();
const controller = require("../../controllers/controller.js");
const passport = require("../../config/passport");
router.post(
"/login",
passport.authenticate("local", { failureRedirect: "/login" }),
function(req, res) {
console.log(`req body -${req.body}`);
res.json({
message: "user authenticated",
});
}
);
router.post("/saveRecipe", (req, res) => {
console.log(req.user)
if (req.isAuthenticated()) {
controller.saveRecipe;
} else {
res.json({ message: "user not signed in" });
}
});
module.exports = router;
The problem is in your router.post('login'). Try changing it to something like this:
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login/failed'})
)
This will correctly set the req.user in your next requests!
I've been trying to test the protected routes by using passport and passport-jwt.
I've got it to the point where the token is being generated when a user tries to log in and tested it in Postman.
I've created a route and passed in as an argument passport.authenticate with the jwt strategy and am getting errors all over the place.
In my main server.js, I require passport:
passport = require('passport');
app.use(passport.initialize());
// passport config
require('./config/passport')(passport);
My folder structure is this:
in my passport config file, i have this:
const jwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const User = mongoose.model('users')
const keys = require('../config/keys');
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
module.export = passport => {
passport.use(
new jwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
}));
};
And my route is this:
// #route get to /users/current
// #desc: return the current user (who the jwt token belongs to)
// #access: should be public
router.get('/current',
passport.authenticate('jwt', { session: false }),
(req, res) => {
res.json({msg: "Success"})
}
);
The first error I can't seem to get passed is this in the console:
require('./config/passport')(passport);
^
TypeError: require(...) is not a function
In postman, when I try to go to /users/current and pass in a confirmed bearer token, I get this:
Error: Unknown authentication strategy "jwt" at attempt
in passport config file
you have typo module.export actualy its module.exports
thats why after require it does not recongnizing it as function
change the module.export to
module.exports = passport => {
passport.use(
new jwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
}));
};
its module.exports and not module.export.
The module.exports property can be assigned a new value (such as a function or object).
module.exports = class Square {
constructor(width) {
this.width = width;
}
area() {
return this.width ** 2;
}
};
nodejs modules documentation reference
im struggled with this problem like more then 40 hours and sill don't know how to solve this, the problem is a little big to explain but i will try my best, im a little newbie with Node.Js and mongo stuffs so forgive me any stupid mistake.
I followed the book Mean Stack and the problem appears when i started this tutorial to do the autentication with auth, i am at the beginning doing the local authentication without any social at the moment.
folder structure
so basicly i set the server like this:
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var mongoose = require('./config/mongoose');
var express = require('./config/express');
var db = mongoose();
var app = express();
app.listen(3000);
module.exports = app;
console.log("running at port 3000");
this is the ./config/mongoose
var config = require('./config');
var mongoose = require('mongoose');
var connectionString = "mongodb://localhost:27017/ShareIdea"
module.exports = function(){
mongoose.Promise = global.Promise;
var db = mongoose.connect(connectionString);
require('../app/models/user.server.model');
return db;
};
the required user.server model
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
local : {
email : String,
password : String,
},
facebook : {
id : String,
token : String,
email : String,
name : String
},
twitter : {
id : String,
token : String,
displayName : String,
username : String
},
google : {
id : String,
token : String,
email : String,
name : String
}
/*firstname:String,
lastname:String,
email:String,
username:String,
password:String,
userChoice: {type: String, possibleValues: ['programmer','inovator']}*/
});
UserSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
UserSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
mongoose.model('User',UserSchema);
here is the express configuration
var config = require('./config');
var express = require('express');
var passport = require('passport');
var flash = require('connect-flash');
var compress = require('compression');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var bodyParser = require('body-parser');
var morgan = require('morgan');
var methodOverride = require('method-override');
var expressLayouts = require('express-ejs-layouts');
module.exports = function(){
var app = express();
**require('./passport')(passport);**
if(process.env.NODE_ENV === 'development')
{
app.use(morgan('dev'));
}
else if(process.env.NODE_ENV === 'production')
{
app.use(compress());
}
app.use(cookieParser());
app.use(bodyParser.urlencoded({
extended:true
}));
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(session({
saveUninitialized: true,
resave: true,
secret: 'aaaaaaa'
}));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash());
app.set('views', './app/views');
app.set('view engine','ejs');
app.use(expressLayouts);
require('../app/routes/index.server.routes.js')(app,passport);
require('../app/routes/register.server.routes.js')(app,passport);
require('../app/routes/login.server.routes.js')(app,passport);
require('../app/routes/profile.server.routes.js')(app,passport);
app.use(express.static('./public'));
return app;
}
here in the express is where the problems appear, this line is the main problem at the moment: `require('./passport')(passport);
if i put this code it gives me the problem that i mentioned in the title, if not when i do a POST request with my form it never posts, i have this troubles because i set the structures of my code to a MVC structure like the book and want to adapt the authentication in the tutorial to my code to learn a little,
so basicly im passing the passport to my routes like this:`
register route
var register = require('../../app/controllers/register.server.controller');
module.exports = function(app,passport) {
app.route('/register')
.post(function(req,res){
console.log("HY");
passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/register', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
})})
.get(register.getPage);
};
Register controller
var User = require('mongoose').model('User');
module.exports = {
getPage: function(req,res){
res.render('./pages/register',{ message: req.flash('signupMessage') });
}
};
and to end here is the passport code:
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var User = require('../app/models/user');
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
};
Ps: Sorry for the long post, i hope i can get a explanation since i want to learn more, when i read the book i felt like the mvc structure adapted by the autor was dificult, but anyways thanks a lot.
if you guys want to not look at this i understand and here is the gitProject:git project
Try this in your user.server.model.js file. Instead of just
mongoose.model('User',UserSchema);
Try this below to have it accessible.
module.exports = {
User : mongoose.model('User', UserSchema)
}
I'm trying to set up Express routes bound with multiple controllers, of course they're supposed to receive functions, this is what I'm trying:
authRouter.get('/login/redirect/:provider', controllers.handleOAuth2Redirect, controllers.jwt);
This has sometimes worked, sometimes not, the only changes when works or not are minimal code changes, could be a require line, an expression, etc.
This is the error being thrown:
Error: Route.get() requires callback functions but got a [object Object]
So following code is the complete working controllers file:
'use strict';
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy = require('passport-twitter').Strategy;
var InstagramStrategy = require('passport-instagram').Strategy;
var OAuth2Strategy = require('passport-oauth2').Strategy;
var facebook_scope = ['email', 'user_about_me','user_friends','publish_actions'];
var passportFacebookOptions = {scope: facebook_scope};
passport.use(new FacebookStrategy({
clientID: process.env.FACEBOOK_FINALCUT_APP_ID,
clientSecret: process.env.FACEBOOK_FINALCUT_APP_SECRET,
callbackURL: 'http://localhost:9248/auth/login/redirect/fb'
},
function (accessToken, refreshToken, params, profile, done) {
return done(null, profile, params);
}));
passport.use(new InstagramStrategy({
clientID: process.env.INSTAGRAM_FINALCUT_CLIENT_ID,
clientSecret: process.env.INSTAGRAM_FINALCUT_CLIENT_SECRET,
callbackURL: 'http://localhost:9248/auth/login/redirect/ig'
},
function (accessToken,refreshToken,profile,done) {
return done(null, profile, {tokens: {accessToken: accessToken, refreshToken: refreshToken}});
}));
function oauth2ProviderLogin (request,response,next) {
var provider = request.query.provider;
switch (provider) {
case 'fb':
passport.authenticate('facebook')(request,response,next);
break;
case 'ig':
passport.authenticate('instagram')(request,response,next);
break;
}
}
function handleOAuth2Redirect (request,response,next) {
var provider = request.params.provider;
switch (provider) {
case 'fb':
passport.authenticate('facebook', {session:false})(request,response,next);
break;
case 'ig':
passport.authenticate('instagram', {session:false})(request,response,next);
break;
}
}
function jwt (request,response,next) {
var jwt = require('jsonwebtoken');
var token = jwt.sign({auth: request.authInfo}, '623145ca-7749-11e5-8bcf-feff819cdc9f');
return response.send({user: request.user, auth: token});
}
module.exports = (function() {
var authController = {
oauth2ProviderLogin: oauth2ProviderLogin,
handleOAuth2Redirect: handleOAuth2Redirect,
jwt: jwt
};
return authController;
})();
I've literally made it work by changing some lines of the controller functions. But the exports block has always remained the same. Naturally I nede to keep coding but then it stops working.
An example of something making it to stop working:
'use strict';
var passport = require('passport');
var jwt = require('jsonwebtoken'); // This makes it fail
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy = require('passport-twitter').Strategy;
var InstagramStrategy = require('passport-instagram').Strategy;
var OAuth2Strategy = require('passport-oauth2').Strategy;
That's it: adding a var jwt = require('jsonwebtoken') will make it fail.
Is there something I'm missing?
My error is actually silly:
Adding var jwt = require('jsonwebtoken') because I have a function with same name below:
function jwt (request,response,next) {
var token = jwt.sign({auth: request.authInfo}, '623145ca-7749-11e5-8bcf-feff819cdc9f');
return response.send({user: request.user, auth: token});
}
Just changing the name of any of those will fix the issue.
I use the following passportjs LocalStrategy:
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(username, password, done) {
// ...
}
));
All works fine if I do provide email and password properties in POST request. But if one of then is empty then this middleware don't get executed but redirect happens.
I need to know what happens and pass req.flash to the client to handle this exception. How could I do it?
You could use express-validator. It can check your email/password fields in general that they are not empty.
Just require and use it in your app.js entry point:
var expressValidator = require('express-validator');
app.use(bodyParser());
app.use(expressValidator()); // then let the app use it, place it HERE after the bodyParser()
and in your login/signup route:
router.post('/signup', function (req, res) {
req.assert('email', 'Email is not valid!').isEmail();
req.assert('password', 'Password is empty!').notEmpty();
var err = req.validationErrors();
if (err) {
req.flash('errors', errors);
return res.redirect('/login');
}
// Your passport here....
}
And then do your passport stuff like login or signup.