passport local strategy not getting called - node.js

I'm sure I'm missing something really obvious here, but I can't figure this out. The function I've passed to the LocalStrategy constructor doesn't get called when the login form gets submitted.
Code:
var express = require('express');
var http = require('http');
var path = require('path');
var swig = require('swig');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.serializeUser(function(user, done) {
console.log('Serialize user called.');
done(null, user.name);
});
passport.deserializeUser(function(id, done) {
console.log('Deserialize user called.');
return done(null, {name: 'Oliver'});
});
passport.use(new LocalStrategy(
function(username, password, done) {
console.log('local strategy called with: %s', username);
return done(null, {name: username});
}));
var app = express();
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'swig');
app.set('views', __dirname + '/views');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('asljASDR2084^^!'));
app.use(express.session());
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.errorHandler({ dumpExceptions:true, showStack:true }));
app.engine('swig', swig.renderFile);
app.post('/auth', passport.authenticate('local'));
app.get('/login', function(req, res) {
// login is a simple form that posts username and password /auth
res.render('login', {});
});
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
The form on my /login page is cut and pasted from the passport docs except that I changed it to submit to /auth instead of /login:
<form action="/auth" method="post">
<div>
<label>Username:</label>
<input type="text" name="username"/>
</div>
<div>
<label>Password:</label>
<input type="password" name="password"/>
</div>
<div>
<input type="submit" value="Log In"/>
</div>
</form>
When I sumit the login form, the following gets logged
GET /login 200 5ms - 432b
POST /auth 401 6ms
Note that "local strategy called" is never logged.
Why isn't the function I passed to LocalStrategy getting called?

I recently came across this problem and it can be caused by a number of things. First thing to check is ensuring that the bodyParser is set up for express, which I see that you have done.
app.use(express.bodyParser());
The next thing is ensuring that the form you are submitting to the route contains both a username AND password, and the user must also enter something in both fields. I was stumped for a bit testing it and not actually putting anything in the password field while testing :) Passport requires BOTH to execute the LocalStrategy verification function passed to passport.authenticate('local').
Your example also seems to be set up to capture both username and password properly, but in any case, you should try testing that the body is being parsed properly even without passport:
app.post('/auth', function(req, res){
console.log("body parsing", req.body);
//should be something like: {username: YOURUSERNAME, password: YOURPASSWORD}
});
Else
Did you try adding a request handler to your /auth route?
app.post('/auth', passport.authenticate('local'), function(req, res){
console.log("passport user", req.user);
});
or
app.post('/auth', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/auth' }));

I encountered the same problem when I set up my own route handler from which I called passport.authenticate (). I forgot that passport.authenticate returns middleware that must be invoked, so just calling passport.authenticate isn't sufficient. Then I replaced
router.post("/",
function(req,res,next){
passport.authenticate("local", function(err, user, info){
// handle succes or failure
});
})
with
router.post("/",
function(req,res,next){
passport.authenticate("local", function(err, user, info){
// handle succes or failure
})(req,res,next);
})

You get 401 when you using different username, password input fields than the default ones. You have to provide that in your LocalStrategy like this :
passport.use(new LocalStrategy({
usernameField: 'login',
passwordField: 'password'
},
function(username, password, done) {
...
}
));
Default is username and password I think. See the docs here.

I think you submit the form with username or password field empty.
If you fill both inputs then submit, LocalStrategy will be called.

For Express 4.x:
// Body parser
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
app.use(bodyParser.json()) // parse application/json
c.f. https://github.com/expressjs/body-parser

I also banged my head for the same problem for few hours. I was having everything in place as told by other answers like
1. Form was returning all fields.
2. body parser was setup correctly with extended:true
3. Passport with every setting and configuration.
But i have changed username field with phoneNumber and password. By changing code like below solved my problem
passport.use('login', new LocalStrategy(
{usernameField:'phoneNumber',
passwordField:'password'},
function (username, password, done) {
// your login goes here
})
);
If anyone want i can write the whole authentication procedure for phonenumber using mongodb and passport-local.
Thanks #user568109

My problem was, that I had the enctype='multipart/form-data'. Just change that to multipart='urlencoded'. And I think that will solve it.

To capture both username and passport make sure to add:
app.use(express.urlencoded());
In my case, I was using app.use(express.json()); and was posting the username and password from <form>.

It's possible your request wasn't formatted properly (particularly the body of it) and your username and password weren't being sent when you thought they were.
Here is an example of an API call wrapper that enforces your request body is parsed as json:
Api = {};
Api.request = (route, options) => {
options = options || {};
options.method = options.method || 'GET';
options.credentials = 'include';
if (options.method === 'POST') {
options.headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
};
options.body = JSON.stringify(options.data) || '{}';
}
fetch(absoluteUrl + '/api/' + route, options)
.then((response) => response.json())
.then(options.cb || (() => {}))
.catch(function(error) {
console.log(error);
});
};
It can be used this way:
Api.request('login', {
data: {
username: this.state.username,
password: this.state.password
},
method: 'POST',
cb: proxy((user) => {
console.log(user);
}, this)
});

For me everything was setup properly.. The issue was that I was collecting form data and then creating a json from form data and send it like JSON.stringify(formdatajson) to server. (For me login form was a popup on screen)
I Found my mistake by debugging passportjs...
If you also have same problem and none of the above solution seems working for you then debug passportjs.
open
strategy.js
put debugger in below method.
Strategy.prototype.authenticate
Check what form data is coming for you.
Hope this help ...

npm install passport-local
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
According to passportjs.org and it worked for me!

Yet another possiblity: For me I had accidentally defined my routes before my body-parser middleware so body-parser was never active for the login route.

Hope it always someone - in my case it was the fact that I tried I used passport middleware before cookieParser and express-session ones
This was my code:
passportConfig(app);
app.use(cookieParser());
app.use(session({ secret: 'bla' }));
Changed passportConfig to be down and it worked:
app.use(cookieParser());
app.use(session({ secret: 'bla' }));
passportConfig(app);

For me it wasn't working because i'd set different name in my login form to that in my passport.js ,It worked for me when i changed user.name in serializeUser to user.username.
passport.serializeUser(function (user, done) {
done(null, user.username)
})
passport.deserializeUser(function (username, done) {
Users.findOne({
username: username
}).then((user) => {
if (!user) {
return done(new Error("No such user"))
}
return done(null, user)
}).catch((err) => {
done(err)
})
})

Check your form in your views if you included a name property in the form or input type and it corresponds to the arguments passed to the localStrategy callback function.

Related

Passport does not call the authentication strategy

today I was trying to get a passport authentication working. The email and password is static now but I will change that later. I have a lot of debug messages but only the ones outside of the Strategy. No errors or warnings regarding passport are displayed.
I have already tried to use different body parser modes (extented = true, extented = false).
Strategy
const LocalStrategy = require('passport-local').Strategy;
module.exports = function(passport) {
passport.use(
new LocalStrategy((email, password, done) => {
console.log('Authentication started');
var user = null;
if(email == 'test#mytest.com') {
if(password == 'test') {
user = {
email
}
console.log('Authenticated')
return done(null, user);
}
}
console.log('Error')
return done(null, user, {message: 'EMail or Password was wrong'});
})
);
passport.serializeUser(function(user, done) {
done(null, user.email);
});
passport.deserializeUser(function(id, done) {
done(err, user);
});
};
app.js (contains only important parts)
const express = require('express');
const expressSession = require('express-session')
const bodyParser = require('body-parser');
const expressLayouts = require('express-ejs-layouts');
const app = express();
const https = require('https');
const http = require('http');
app.use(expressSession({ secret: 'secret' }));
// Body Parser
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());
// Passport
const passport = require('passport');
require('./config/passport')(passport);
app.use(passport.initialize());
app.use(passport.session());
// View Engine
app.set('view engine', 'ejs');
app.use(expressLayouts);
app.get('/applications', (req,res) => {
res.render('applications', {
user: req.user
});
});
app.post('/applications', (req, res, next) => {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/applications',
failureRedirect: '/',
failureFlash: false
})(req, res, next);
});
https.createServer(httpsOptions, app)
.listen(7443, () => {
console.log('HTTPS Server started on Port 7443')
});
http.createServer(app)
.listen(7080, () => {
console.log('HTTP Server started on Port 7080')
});
Make sure you are using the proper fields in your POST request. I noticed that in your strategy, you use the variables email and password. While your variable names aren't important, the fields you send in your POST request are. By default, passport-local uses the POST fields username and password. If one of these fields aren't present, the authentication will fail. You can change this to use email instead like so:
passport.use(
new LocalStrategy({
usernameField: 'email'
}, (email, password, done) => {
console.log('Authentication started');
// Your authentication strategy
})
);
Assuming you have the right POST fields, in order to use req.user in requests, you must have properly set up your passport.deserializeUser function. Testing your code, the authentication strategy is working fine for me, however I receive a reference error upon deserializeUser.

Passport js serializeUser & deserializeUser

I have read everything on the argument but still cannot understand it. The documentation on the Passport Js web site is very vague.
I am using Passport JS with the passport-ldapauth Strategy. I do not have a Database. I obviously don't want to hit the LDAP server on each request. I would like to authenticate the user the first time on the POST /login route using the passport strategy with LDAP, store the user in the session and on each subsequent requests I just want to check if the user is already logged in.
I am trying to use the session but I cannot understand how to use Passport + session with the serialize/deserialize flow. Every example I checked use a User.findOne in the deserializeUser function.
As of now I disabled the use of the session for Passport and I am using a custom middleware where I check if req.session.user != null. If that's the case the user is already logged in and I hit next(). Otherwise redirect to login.
Here is some code (for sake of simplicity I deleted the code not related to the question):
Passport configuration:
var express = require('express'),
session = require('express-session'),
passport = require('passport'),
LdapStrategy = require('passport-ldapauth');
var app = express();
var LdapStrategyOptions = {
server: {
url: '<url>',
bindDN: '<dn>',
bindCredentials: "<pwd>",
searchBase: '<searchBase>',
searchFilter: '<filter>'
}
};
passport.use(new LdapStrategy(LdapStrategyOptions));
app.use(cookieParser());
app.use(session({
store: new LokiStore({autosave: false}),
resave: false,
saveUninitialized: false
secret: env.get("SESSION_SECRET")
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
Routes:
// LOGIN ROUTE
app.get('/login',
function(req, res) {
res.render('login');
});
// LOGIN HANDLER ROUTE
app.post('/login',
passport.authenticate('ldapauth', { session: false }),
function(req, res) {
req.session.userId = req.user.cn;
req.session.user = {
"userId": req.user.cn,
"displayName": req.user.displayName
};
res.redirect('/');
});
// LOGOUT ROUTE
app.get('/logout',
function(req, res) {
req.session.destroy(function(err) {
req.logout();
res.redirect('/');
});
});
// HOME ROUTE
app.get('/', isLoggedIn, function(req, res) {
res.render('home');
});
IsLoggedIn Middleware:
var isLoggedIn = function(req, res, next) {
if (req.session.user != null){
console.log("is auth ok '" + req.session.user.userId +"'");
return next();
}
console.log("redirect to auth/login");
res.redirect('/auth/login');
}
What am I missing? Is there any security fault in my setup?
Any help is appreciated.
From passportjs docs:
In a typical web application, the credentials used to authenticate a user will only be transmitted during the login request. If authentication succeeds, a session will be established and maintained via a cookie set in the user's browser.
Each subsequent request will not contain credentials, but rather the unique cookie that identifies the session. In order to support login sessions, Passport will serialize and deserialize user instances to and from the session.
Basically serializeUser is supposed to return a unique user identifier so you can deserializeUser back into JSON later.
So for your implementation you should probably do something along these lines:
DISCLAIMER: I have no experience with LDAP.
passport.serializeUser(function(user, done) {
//We can identify the user uniquely by the CN,
//so we only serialize this into the session token.
done(null, user.cn);
});
passport.deserializeUser(function(cn, done) {
//Directly query LDAP.
//I'm not sure passport caches the result (only calls deserializeUser for new sessions)
//but worst case you can cache the result yourself.
somehowLoadUserFromLDAPByCN(cn, function(err, user) {
done(err, {
userId: user.cn,
displayName: user.displayName
});
});
});
If you only need an id and a display name, it's totally fine to keep them in session. You should only load the full user profile when you need more fields.

Google-oauth2 passport not working

I am trying to implement sign-in with google and passport but I am running into a bit of a problem. I successfully authenticate with google, but my data isn't being passed to the front end. I Haven't changed anything from the original code except for the URI and necessary client id and secret. Can anyone tell me what I am missing?
var express = require( 'express' )
, app = express()
, server = require( 'http' ).createServer( app )
, passport = require( 'passport' )
, util = require( 'util' )
, bodyParser = require( 'body-parser' )
, cookieParser = require( 'cookie-parser' )
, session = require( 'express-session' )
, RedisStore = require( 'connect-redis' )( session )
, GoogleStrategy = require( 'passport-google-oauth2' ).Strategy;
// API Access link for creating client ID and secret:
// https://code.google.com/apis/console/
var GOOGLE_CLIENT_ID = "307841191614-1shiak514mrjugtbon3dm2if8hbhnvdv.apps.googleusercontent.com"
, GOOGLE_CLIENT_SECRET = "fgViegEgHWuoc1X-p63iPmpF";
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing. However, since this example does not
// have a database of user records, the complete Google profile is
// serialized and deserialized.
passport.serializeUser(function(user, done) {
done(null, user);
console.log("User: "+ user.displayName); // If there is a persistent session, the console logs out the displayName
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
// Use the GoogleStrategy within Passport.
// Strategies in Passport require a `verify` function, which accept
// credentials (in this case, an accessToken, refreshToken, and Google
// profile), and invoke a callback with a user object.
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
//NOTE :
//Carefull ! and avoid usage of Private IP, otherwise you will get the device_id device_name issue for Private IP during authentication
//The workaround is to set up thru the google cloud console a fully qualified domain name such as http://mydomain:3000/
//then edit your /etc/hosts local file to point on your private IP.
//Also both sign-in button + callbackURL has to be share the same url, otherwise two cookies will be created and lead to lost your session
//if you use it.
callbackURL: "http://127.0.0.1:3000/oauth2callback",
passReqToCallback : true
},
function(request, accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// To keep the example simple, the user's Google profile is returned to
// represent the logged-in user. In a typical application, you would want
// to associate the Google account with a user record in your database,
// and return that user instead.
console.log(profile); //logs google profile successfully
return done(null, profile);
});
}
));
// configure Express
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use( express.static(__dirname + '/public'));
app.use( cookieParser());
app.use( bodyParser.json());
app.use( bodyParser.urlencoded({
extended: true
}));
app.use( session({
secret: 'cookie_secret',
name: 'kaas',
store: new RedisStore({
host: '127.0.0.1',
port: 6379
}),
proxy: true,
resave: true,
saveUninitialized: true
}));
app.use( passport.initialize());
app.use( passport.session());
/*
===
===
===
Here is where the data is not being read.
*/
app.get('/', function(req, res){
res.render('index', { user: req.user });
console.log(req.user); //Output: undefined
});
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { user: req.user });
});
app.get('/login', function(req, res){
res.render('login', { user: req.user });
});
// GET /auth/google
// Use passport.authenticate() as route middleware to authenticate the
// request. The first step in Google authentication will involve
// redirecting the user to google.com. After authorization, Google
// will redirect the user back to this application at /auth/google/callback
app.get('/auth/google', passport.authenticate('google', { scope: [
'https://www.googleapis.com/auth/plus.login',
'https://www.googleapis.com/auth/plus.profile.emails.read']
}));
// GET /auth/google/callback
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
app.get( '/oauth2callback',
passport.authenticate( 'google', {
successRedirect: '/',
failureRedirect: '/login'
}));
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
server.listen( 3000 );
// Simple route middleware to ensure user is authenticated.
// Use this route middleware on any resource that needs to be protected. If
// the request is authenticated (typically via a persistent login session),
// the request will proceed. Otherwise, the user will be redirected to the
// login page.
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login');
}
`
Here is the simple layout that doesn't seem to be receiving any data.
<% if (!user) { %>
<h2>Welcome! Please log in.</h2>
<% } else { %>
<h2>Hello, <%= user.displayName %>.</h2>
<% } %>
Your code works, I just used same example on my app.
I had the same problem and I realized that I'm not using a valid account in my tests.
This API retrieves data from Google+ profile. Are you using a valid Google account with linked Google+ profile to authenticate?

Node.js / express - using passport with redis, getting session unauthorized

I'm trying to use redis with express to create a user login and session. I test the route using this curl script:
curl -d 'email=testEmail&password=testPass' http://localhost:3000/users/session
When I do this, passport works fine through serialization, and then it returns http 302. I haven't figured out what it does after serialization, but when I try it in the browser with my login html form instead of curl, It shows me "Unauthorized" 401, and I don't see any of my console logs. Here's my app.js:
var express = require('express')
, fs = require('fs')
, cons = require('consolidate')
, http = require('http')
, flash = require('connect-flash')
, passport = require('passport')
, RedisStore = require( "connect-redis" )(express) //for sessions (instead of MemoryStore)
, redis = require('redis')
, env = process.env.NODE_ENV || 'development'
, config = require('./config/config')[env]
, db = redis.createClient(config.db.port, config.db.host);
db.select(config.db.users)
db.auth(config.db.auth);
var app = express();
//require passport strategies (see code block below)
require('./config/passport')(passport, config, app)
app.use('/assets', express.static(__dirname + '/public'));
app.use('/', express.static(__dirname + '/'));
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
app.configure(function(){
app.set('config', config);
app.set('db', db);
app.set('port', process.env.PORT || 3000);
app.engine('.html', cons.swig);
app.use(express.logger('dev'))
app.use(express.favicon(__dirname + '/public/img/favicon.ico'));
app.use(express.cookieParser())
app.use(express.bodyParser()) //enables req.body
app.use(express.methodOverride()) //enables app.put and app.delete (can also just use app.post)
app.use(express.session({
secret: 'topsecret',
cookie: {secure: true, maxAge:86400000},
store: new RedisStore({
client:db,
secret:config.db.auth
})
}));
app.use(flash())
app.use(passport.initialize())
app.use(passport.session())
app.use(app.router)
});
// Bootstrap routes
require('./config/routes')(app, passport);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port')+', mode='+env);
});
And the session POST route:
app.post('/users/session', passport.authenticate('local', {successRedirect: '/', failureFlash: 'Invalid email or password.', successFlash: 'Welcome!'}), users.session);
I could only really find examples of passport with mongodb, so I'm not sure about the following. I attempt to find a user, but I'm not sure about the callbacks or what passport is doing with the user info when I return done:
passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'password' },
function(email, password, done) {
var db = app.get('db')
var multi = db.multi();
db.get('email:'+email, function(err, uid){
if (err) { console.log(err); return err }
if (!uid) { console.log('no uid found'); return null }
console.log('found '+uid)
db.hgetall('uid:'+uid, function(err, user){
if (err) { console.log(err); return err }
if (!user) {
console.log('unkwn usr')
return done(null, false, { message: 'Unknown user' })
}
if (password != user.password) {
console.log('invalid pwd')
return done(null, false, { message: 'Invalid password' })
}
console.log('found user '+user) //I see this fine with curl, but no logs with browser
return done(null, user)
});
});
}
))
Passport serialization:
passport.serializeUser(function(user, done) {
console.log('passport serializing...'+user.name)
done(null, user.name) //no idea what happens to it after this. returns a 302 with curl, and 401 with browser
})
Why does this act differently with a browser than with curl? Any help or comments much appreciated!
Figured it out! To use passport with any database (not just mongo), I would recommend trying it with a dummy user first. Here's what I did.
Login Form (login.html):
<form method="post" action="http://localhost:3000/users/session" name="loginform">
<input id="login_input_username" type="text" name="email" />
<input id="login_input_password" type="password" name="password" autocomplete="off" />
<input type="submit" name="login" value="Submit" />
</form>
Routing (route.js):
app.post('/users/session', passport.authenticate('local'),
function(req, res){
res.end('success!');
});
Passport Local Strategy setup (passport.js):
passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'password' },
function(email, password, done) {
//find user in database here
var user = {id: 1, email:'test', password:'pass'};
return done(null, user);
}
));
passport.serializeUser(function(user, done) {
//serialize by user id
done(null, user.id)
});
passport.deserializeUser(function(id, done) {
//find user in database again
var user = {id: 1, email:'test', password:'pass'};
done(null, user);
})
Although I'm wondering if it's necessary to find user in my database twice, or if I'm using deserialize incorrectly.

Twitter authentication with Passport middleware in Node

I'm developing a website with Node.js (using Express framework). In order to use Twitter authentication, I'm using passport module (http://passportjs.org), and his wrapper for Twitter called passport-twitter.
My server-side script is:
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path')
, passport = require('passport')
, keys = require('./oauth/keys')
, TwitterStrategy = require("passport-twitter").Strategy;
var app = express();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('foo'));
app.use(express.session());
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
});
app.configure('development', function(){
app.use(express.errorHandler());
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
passport.use(new TwitterStrategy({
consumerKey: keys.twitterConsumerKey,
consumerSecret: keys.twitterConsumerSecret,
callbackURL: "http://local.host:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
User.findOrCreate({ twitterId: profile.id }, function (err, user) {
if (err) { return done(err); }
else { return done(null, user); }
});
}
));
app.get('/', routes.index);
app.get('/contacts', routes.contacts);
app.get('/cv', routes.cv);
app.get('/projects', routes.projects);
app.get('/users', user.list);
// Redirect the user to Twitter for authentication.
// When complete, Twitter will redirect the user back to the
// application at /auth/twitter/callback
app.get('/auth/twitter', passport.authenticate('twitter'));
// Twitter will redirect the user to this URL after approval. Finish the
// authentication process by attempting to obtain an access token. If
// access was granted, the user will be logged in. Otherwise,
// authentication has failed.
app.get('/auth/twitter/callback',
passport.authenticate('twitter',
{
successRedirect: '/',
failureRedirect: '/login'
}
)
);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
The URI associated to login is http://local.host:3000/auth/twitter; when I visit it, Twitter shows me the authentication form for linking my account with my own website but, after this step, the following error occurs:
Express
500 ReferenceError: User is not defined
How can I solve this problem?
Best regards, Vi.
You have to define your User type somewhere. It looks like you expect this thing User to exist and to have the functions findOrCreate and findById, but you never defined that anywhere. Where are you 'finding' these users? The ones that aren't found, where are they being 'created'? Are you using a database? How do you connect to the database? I think you forgot the "Model" step. You might want to take a look at Mongoose Auth which is like Passport but it plugs directly into Mongoose, which connnects to a Mongo Database
This is what I did when I faced the same error which says User isn't defined:
passport.use(new TwitterStrategy({
consumerKey: keys.twitterConsumerKey,
consumerSecret: keys.twitterConsumerSecret,
callbackURL: "http://local.host:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
done(null, profile);
}
));
I ran into the same issue when integrating the BeatsMusic OAuth2 strategy for Passport within Kraken. It looks like the examples for the various Kraken Passport integration strategies use the same simple example documentation which did not explicitly discuss the User object (understandable).
I figured out (from digging thru the passport strategy examples found # https://github.com/krakenjs/kraken-examples/tree/master/with.passport) that the User is intended to be a model based on the Mongoose model schema and also is configured with the https://github.com/drudge/mongoose-findorcreate plugin.
After i included the User = require('../PATH_TO/user') and added this plugin to the User model, voila! no more errors :)
Sounds like you don't need the DB functionality so you are probably good with removing the auth check.
Hope this helps for anyone else having similar issues.
I think the api is not ready for the cases not need User's db integration. My solution was ignore the done() function and make a redirect to the success page.
passport.use(new TwitterStrategy({
consumerKey: keys.twitterConsumerKey,
consumerSecret: keys.twitterConsumerSecret,
callbackURL: "http://local.host:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
//done(null, profile);
this.redirect('/auth/success');
}
));
To further explain on Max's answer: "You need to Create User yourself"
Read Here
TL:DR - Basically you have to have a userschema that you use to set users and verify users, it needs a mongoose db backend, which is actually simple to configure.
essentially creating this middleware:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// define the schema for our user model
var userSchema = mongoose.Schema({
local : {
email : String,
password : String,
group : 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
}
});
// methods ======================
// generating a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);

Resources