I have some login page, as soon as the authenticated get success, in the next page, I should display Login Details.. ( ie., username and password )
I'm using Express NodeJs, Passport, connect-flash, mongoose
My prob is: I'm unable to understand how to retrieve username, password in the next rendered page..
Please someone suggest me how to achieve it. I'm not asking you code, BUT show me a way to get my output.
EDIT:
app.js
var http = require('http');
var express = require('express'),
passport = require('passport')
, LocalStrategy = require('passport-local').Strategy,
flash = require('connect-flash'),
User = require('./routes/userdao.js');
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ uname: username ,pwd:password}, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
var app = express();
app.configure(function(){
app.use(express.logger('dev')); /* 'default', 'short', 'tiny', 'dev' */
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'mysecret' }));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.engine('.html', require('ejs').__express);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
app.use(app.router);
// app.use(express.errorHandler());
}).listen(3000);
console.log('Listening on port 3000...');
app.get('/',function(req,res){
/* req.flash('info', 'Flash is back!')
res.redirect('/success');*/
res.render('home.ejs');
});
app.get('/login',function(req,res){
res.render('login.ejs');
});
app.get('/success',function(req,res){
res.render('success.ejs',{ uname : req.user.username });
});
app.post('/login',
passport.authenticate('local', { successRedirect: '/success', failureRedirect: '/login',
failureFlash: true }));
success.ejs
<%= uname %>
I'm trying to display username which I entered in the login page.. I'm getting output: undefined
please tell me what went wrong and what I need to correct?
In the most general sense, if authentication succeeds the user object you return from authenticate ends up at req.user in your downstream functions.
http://passportjs.org/guide/authenticate/
And then, assuming you are using sessions, any subsequent requests will also expose req.user based on your serializeUser/deserializeUser functions.
Related
I have a server in node.js using express and passport with the passport-local strategy.
I have the users in the database and through passport I'm able to authenticate them, unfortunately when a second request comes from the same client the req.isAuthenticated() method returns false.
There is also no user in the request (req.user = undefined).
I've also checked and when doing the authentication although I get back a user from passport.authenticate('local'... I do not get req.user populated then. If I try to set it up manually it just doesn't propagate for following requests.
I don't understand what I'm doing wrong, here is my code.
server.js
var express = require('express'),
compass = require('node-compass'),
routes = require('./server/routes')
http = require('http'),
path = require('path'),
passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
Database = require('./server/repositories/database'),
Configuration = require('./server/config').Config,
crypto = require('crypto');
var app = express();
app.enable("jsonp callback");
passport.use(new LocalStrategy(
function(email, password, done) {
process.nextTick(function () {
var userService = new UserService();
userService.login(email, crypto.createHash('md5').update(password).digest("hex"), function(error, user) {
if (error) done(error, user);
else if (!user) return done(null, false, { message: 'wrong credentials'});
return done(null, user);
});
});
}
));
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
var userService = new UserService();
userService.findById(id, function(err, user) {
done(err, user);
});
});
app.configure(function(){
app.set('port', Configuration.Port);
app.set('views', __dirname + '/app/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(compass({
project: path.join(__dirname, 'app'),
sass: 'styles'
}));
app.use(express.session({ secret: 'keyboard cat' }));
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'app')));
});
routes.configure(app);
Database.open(function() {
app.listen(Configuration.Port, function() {
console.log("Express server listening on port " + Configuration.Port);
});
});
routes.js
var Configuration = require('./config').Config;
var ApiResult = require('../model/apiResult').ApiResult;
var ApiErrorResult = require('../model/apiErrorResult').ApiErrorResult;
var ApiReturnCodes = require('../model/apiReturnCodes').ApiReturnCodes;
var passport = require('passport');
var usersController = require('./controllers/usersController');
exports.configure = function(app) {
function ensureAuthenticated(req, res, next) {
console.log(req.isAuthenticated());
if (req.isAuthenticated()) { return next(); }
else {res.send(new ApiErrorResult(ApiReturnCodes.NOT_LOGGED_IN, null));}
}
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err || !user) { console.log(info); res.send(new ApiErrorResult(ApiReturnCodes.ENTITY_NOT_FOUND, null)); }
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user
else res.send(new ApiResult(user));
})(req,res,next);
});
app.get('/anotherLink', ensureAuthenticated, function(req, res, next) {
res.json({Code:0});
});
}
When I hit the link /anotherLink after being authenticated I get res.isAuthenticated() as false.
Also when I see the req.session after the ensureAuthenticated is called I get:
{ cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: {} }
What am I missing for it to save the information that that user is authenticated?
On the client side I'm using Angular only doing a simple get with the url without parameters.
If I forgot to put something here just tell me, I'll update it.
Any help will be greatly appreciated. Thanks
So I found out what was wrong with my code.
My passport.deserializeUser method used the method userService.findById
And that called the repository... like this:
userRepository.findUnique({"_id": id}, callback);
because the id was generated by MongoDB the correct call needs to be:
userRepository.findUnique({"_id": new ObjectID(id)}, callback);
I hope this saves some time to the next person with the same problem.
With this detail, this code should work nicely for everyone wanting to use the LocalStrategy on the Passport framework.
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.
I am using the following code to authenticate users with passport js
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes')
, http = require('http')
, path = require('path');
var app = express();
var config = require('./config');
var User = require('./models/user');
var passport = require('passport'),
FacebookStrategy = require('passport-facebook').Strategy;
//setting up passport
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 FacebookStrategy({
clientID: config.development.fb.appid,
clientSecret: config.development.fb.appSecret,
callbackURL: config.development.fb.url + 'fbauthed'
},
function (accessToken, refreshToken, profile, done) {
User.findOne({
'fbId': profile.id
}, function (err, oldUser) {
if (oldUser) {
console.log('Existing user: ' + oldUser.name + ' found and logged in');
done(null, oldUser);
} else {
var newUser = new User();
newUser.fbId = profile.id;
newUser.name = profile.displayName;
newUser.email = profile.emails[0].value;
newUser.username = profile.username;
console.log(profile);
newUser.save(function (err) {
if (err) throw err;
console.log('New user:' + newUser.name + 'created and logged in');
done(null, newUser);
});
}
});
}
));
app.configure(function(){
app.set('port', process.env.PORT || 5000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.cookieParser());
app.use(express.session({secret: 'big secret'}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
app.configure('development', function(){
app.use(express.errorHandler());
});
app.get('/', routes.index);
app.get('/fbauth', passport.authenticate('facebook', {scope: 'email'}));
app.get('/fbauthed', passport.authenticate('facebook',{ failureRedirect: '/'}), routes.loggedin);
app.get('/logout', function(req,res){
req.logOut();
res.redirect('/');
});
//app.get('/users', user.list);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
The above code works great for when users are authenticating, however after authentication a page refresh throws an error like below.
Express
500 failed to obtain access token (status: 400 data: {"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100}})
at /home/colm/javascript/facebookauth/node_modules/passport-facebook/node_modules/passport-oauth/lib/passport-oauth/strategies/oauth2.js:125:38
at exports.OAuth2.getOAuthAccessToken (/home/colm/javascript/facebookauth/node_modules/passport-facebook/node_modules/passport-oauth/node_modules/oauth/lib/oauth2.js:131:18)
at passBackControl (/home/colm/javascript/facebookauth/node_modules/passport-facebook/node_modules/passport-oauth/node_modules/oauth/lib/oauth2.js:77:9)
at IncomingMessage.exports.OAuth2._request.request.on.callbackCalled (/home/colm/javascript/facebookauth/node_modules/passport-facebook/node_modules/passport-oauth/node_modules/oauth/lib/oauth2.js:94:7)
at IncomingMessage.EventEmitter.emit (events.js:126:20)
at IncomingMessage._emitEnd (http.js:366:10)
at HTTPParser.parserOnMessageComplete [as onMessageComplete] (http.js:149:23)
at CleartextStream.socketOnData [as ondata] (http.js:1447:20)
at CleartextStream.CryptoStream._push (tls.js:544:27)
at SecurePair.cycle (tls.js:898:20)
What is causing this and how can I fix this problem?
Any help would be great. Thanks.
The route which is used to handle the FB callback should only issue a redirect (either back to the login page if the authentication failed, or the 'logged in' page when authentication succeeded).
You're calling routes.loggedin to handle that route (in case of success):
app.get('/fbauthed', passport.authenticate('facebook',{ failureRedirect: '/'}), routes.loggedin);
This will keep all the tokens passed by FB in the URL resulting in the 'This authorization code has been used' message.
So try this:
app.get('/loggedin', ensureLoggedIn('/'), routes.loggedin); // see below
app.get('/fbauthed', passport.authenticate('facebook',{
failureRedirect: '/',
successRedirect: '/loggedin'
}));
ensureLoggedIn is a middleware that will check if the user is logged in, and if not, will redirect to / (or whatever URL you like).
I'm new to Express.js, Node.js, and Passport.js. I'm trying to develop an application where a user signs in with their Twitter account and then they can see their Mentions (Tweets in which other Twitter users have mentioned the logged in user's Twitter username). I came across Passport.js, and I have been able to use it successfully allow a user to sign in with their Twitter account.
However, I am not sure how to format a server-side HTTP GET request for the Twitter Mentions. I've reviewed the Twitter API numerous times at https://dev.twitter.com/docs/api/1/get/statuses/mentions, but since I'm unfamiliar with the Node/Express/Passport platform, I'm not sure how to perform this request server-side to return JSON-formatted Mentions. The application is set up to be read-only, as it only needs to be able to see relevant Tweets with the associated user.
The front-end is based on EJS. Below is what code I have that may be relevant. Thank you very much for your help.
-joshingmachine
/app.js
/**
* Module dependencies.
*/
var express = require('express')
, passport = require('passport')
, http = require('http')
, util = require('util')
, path = require('path')
, TwitterStrategy = require('passport-twitter').Strategy;
var TWITTER_CONSUMER_KEY = "theConsumerKeyForMyApp";
var TWITTER_CONSUMER_SECRET = "theConsumerSecretForMyApp";
var users = [];
// Passport session setup.
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
var user = users[id];
done(null, user);
});
// Use the TwitterStrategy within Passport.
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
//console.log(token);
//console.log(tokenSecret);
//console.log(profile);
// asynchronous verification, for effect...
process.nextTick(function () {
var user = users[profile.id] || (users[profile.id] = profile);
done(null, user);
});
}
));
var app = express();
// configure Express
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({ secret:'secret'}));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.get('/', function(req, res){
res.render('index', { user: req.user });
});
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/twitter
app.get('/auth/twitter',
passport.authenticate('twitter'),
function(req, res){
// The request will be redirected to Twitter for authentication, so this
// function will not be called.
});
// GET /auth/twitter/callback
app.get('/auth/twitter/callback',
passport.authenticate('twitter', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
// Create server
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
// Simple route middleware to ensure user is authenticated.
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login');
}
app.use(function(req, res, next){
res.send(404, '404 Not Found');
});
/routes/index.js
/*
* GET home page.
*/
exports.index = function(req, res){
res.render('index', { title: 'Express' });
};
Install the module:
npm install oauth
Then use this code to create your GET request(replace the variables as needed).
var oauth = new OAuth.OAuth(
'https://api.twitter.com/oauth/request_token',
'https://api.twitter.com/oauth/access_token',
'your application consumer key',
'your application secret',
'1.0A',
null,
'HMAC-SHA1'
);
oauth.get(
'https://api.twitter.com/1.1/trends/place.json?id=23424977',
'your user toke for this app', //test user token
'your user secret for this app', //test user secret
function (e, data, res){
if (e) console.error(e);
console.log(require('util').inspect(data));
done();
});
And reference here if you need more info. Good luck!
https://github.com/ciaranj/node-oauth
I created something similar to what you're trying to do. Since you've signed in succesfully, I'm assuming that you're able to get the access token and secret. Once you have those, use an external library like mtwitter. I made the call like this (editing out the parts where i get the tokens from my db):
app.get('/twitter/userMentions', function (req, res) {
var twit = new mtwitter({
consumer_key: consumerKey,
consumer_secret: consumerSecret,
access_token_key: token,
access_token_secret: secret
});
twit.get("/statuses/mentions_timeline", { "include_entities": false },
function (err, data) {
if (err) {
res.write(err.toString());
}
else res.write(JSON.stringify(data));
res.end('\n');
});
}
I think you are looking for Request node module !!
https://npmjs.org/package/request
I was playing around with node.js as a beginner and trying to get the login/atuthentication running but got stuck there. I then downloaded connect-flash middleware using npm and this is how my server.js looks like:
var express = require('express'),
passport = require('passport'),
util = require('util'),
LocalStrategy = require('passport-local').Strategy,
wines = require('./routes/wines');
var users = [
{ id: 1, username: 'bob', password: 'secret', email: 'bob#example.com' }
, { id: 2, username: 'joe', password: 'birthday', email: 'joe#example.com' }
];
function findById(id, fn) {
var idx = id - 1;
if (users[idx]) {
fn(null, users[idx]);
} else {
fn(new Error('User ' + id + ' does not exist'));
}
}
function findByUsername(username, fn) {
for (var i = 0, len = users.length; i < len; i++) {
var user = users[i];
if (user.username === username) {
return fn(null, user);
}
}
return fn(null, null);
}
// 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.
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
findById(id, function (err, user) {
done(err, user);
});
});
// Use the LocalStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a username and password), and invoke a callback
// with a user object. In the real world, this would query a database;
// however, in this example we are using a baked-in set of users.
passport.use(new LocalStrategy(
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// Find the user by username. If there is no user with the given
// username, or the password is not correct, set the user to `false` to
// indicate failure and set a flash message. Otherwise, return the
// authenticated `user`.
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
});
}
));
var flash = require('connect-flash');
var express = require("express");
var app = express();
app.get('/', function(req, res){
res.render('index', { user: req.user });
});
app.get('/flash', function(req, res){
req.flash('info', 'Flash is back!')
res.redirect('/');
});
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, message: "Hello!"});
});
// configure Express
app.configure(function() {
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({ secret: 'keyboard cat' }));
// 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(express.cookieParser('keyboard cat'));
app.use(express.session({ cookie: { maxAge: 60000 }}));
app.use(flash());
});
// POST /login
// 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.
//
// curl -v -d "username=bob&password=secret" http://127.0.0.1:3000/login
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res) {
res.redirect('/');
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
app.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')
}
app.get('/wines', wines.findAll);
app.get('/wines/:id', wines.findById);
console.log('Listening on port 3000...');
Why do I still get that error? How to fix it?
Move all your app[METHOD] middleware to after all the app.use middleware