passportjs authentication using google apps email id - javascript

I am trying passport js with google app email id. I am able to authenticate using gmail.com email id. But how can I authenticate if the email id is a google app id (google.com/a/companyname.com).
This is my code
var express = require('express');
var app = express();
var passport = require('passport');
var GoogleStrategy = require('passport-google').Strategy;
passport.use(new GoogleStrategy({
returnURL: 'http://10.3.0.52:3000/auth/google/return',
realm: 'http://10.3.0.52:3000/'
},
function(identifier, profile, done) {
User.findOrCreate({
openId: identifier
}, function(err, user) {
done(err, user);
});
}
));
app.get('/auth/google', passport.authenticate('google'));
app.get('/auth/google/return',
passport.authenticate('google', {
successRedirect: '/',
failureRedirect: '/login'
}));
app.get('/', function(req, res){
res.writeHead(200);
res.end("connected");
});
app.listen(process.env.PORT || 3000);

Your code is missing some vital parts:
...
passport.use(...); // this you have
// these are required as well.
app.use(passport.initialize());
app.use(passport.session());
// please read docs for the following two calls
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
...
With those in place, I can log in using my Google App address just fine.
EDIT: it only works with Node 0.8 though, Node 0.10 gives an error. I think using passport-google-oauth is a better solution anyway. For that, you have to register your application with Google (here); after registration, you'll be supplied both the GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET codes which you can use.

I have created a method that verifies if the email domain is the one i want to authorize:
UserSchema.method('checkFordomain', function(value) {
var parts = value.split('#');
return (parts[1] == 'companyname.com');
});
this is method I put in the model of the user model, using mongoose schema models
if (!user.checkForMMdomain(profile.emails[0].value)) {
return done();
}
in the callback of the passport google strategy
https://github.com/jaredhanson/passport-google-oauth

In your passport.use callback you can perform additional checking based on the domain of the primary email address (or whatever you are checking):
if (profile.emails[0].split('#')[1] !== authorizedDomain) {
return done(null, false);
}

Related

req.user is undefined when using PassportJS, SequelizeJS and JWT tokens

I already checked multiple answers here on Stackoverflow, and also went through on the documentation but I still cannot find out what could be the problem. In my application I'm using SequelizeJS to access to my mySQL database and now I'm trying to secure my REST API endpoints with PassportJS using the JWT Strategy.
./app.js
// ...
// passport
app.use(passport.initialize());
require('./config/passport')(passport);
// ...
./config/passport.js
var passport = require('passport');
var passportJwt = require('passport-jwt');
var models = require('../models');
var config = require('./config');
var ExtractJwt = passportJwt.ExtractJwt;
var Strategy = passportJwt.Strategy;
module.exports = function(passport) {
var params = {
secretOrKey: config.jwt.secret,
jwtFromRequest: ExtractJwt.fromAuthHeader()
};
passport.use(new Strategy(params, function(jwt_payload, done) {
models.User.findOne({
where: {
id: jwt_payload.id
}
}).then(
function(user) {
if (user) {
done(null, user);
} else {
done(null, false);
}
},
function(err) {
return done(err, false);
}
);
}));
};
I'm trying to get the user entity from the request of this simple route:
var router = express.Router();
// ...
router.route('/user/me', passport.authenticate('jwt', { session: false }))
.get(function(req, res) {
console.log(req.user);
res.json(req.user);
});
I already created another route which returns a JWT token based on the provided username and password. When I call the /user/me endpoint I attach the JWT token into the header, for example:
Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.M9z3iWNdjAu4THyCYp3Oi3GOWfRJNCYNUcXOw1Gd1Mo
So, my problem is that when I call the /user/me endpoint with a token, the req.user will be undefined and I cannot figure it out what is the reason.
Thank you in advance for your help!
Your route definition seems to be wrong: router.route doesn't accept a middleware in its second argument, so authentication does not happen at all.
It should be smth like
var router = express.Router();
// ...
router.route('/user/me')
.all(passport.authenticate('jwt', { session: false }))
.get(function(req, res) {
console.log(req.user);
res.json(req.user);
});

Passport.js: Sign in with Github and return email address

I have built a node.js web app that uses passport.js with the passport-github strategy. Here is my code:
var express = require('express');
var app = express();
app.use(express.static('public'));
var passport = require('passport');
var GithubStrategy = require('passport-github').Strategy;
passport.use(new GithubStrategy({
clientID: "foo",
clientSecret: "bar",
callbackURL: "baz",
profileFields: ['email']
}, function(accessToken, refreshToken, profile, done) {
return done(null, profile);
}));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
app.use(session({
secret: 'this is a secret',
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.set('view engine', 'ejs');
app.get('/', function(req, res) {
html = JSON.stringify(req.user, null, 4);
res.render('index', {
title: 'My Home Page',
html: html
});
});
//Login
app.get('/login', function(req, res) {
res.render('login', {
title: 'Login to Chordscribble!'
});
});
//Logout
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
// GitHub
app.get('/auth/github', passport.authenticate('github', {
scope: ['user:email']
}));
app.get('/auth/github/callback', passport.authenticate('github', {
failureRedirect: '/login'
}), function(req, res) {
res.redirect('/');
});
app.listen(3000);
Everything is working fine except that I am getting a return value of null for the email address. My first question is, is there a way to guarantee that I will always get an email address? And, my second question is, if not, what how should I store this in a database without an email address? Possibly by assigning my own user id field and using their Github ID? Is the GitHub ID always going to be unique?
If you are using passport-githubStrategy:
You should pass scope: 'user:email', rather than passing profileFields: ['email'] which is passed in the Facebook Passport Strategy.
As #mherzig said you should consider looking for the scope of the OAuth you are using, and Github accepts user:email for passing the emails
So, you should be using this for passport-github strategy:
new GitHubStrategy(
{
clientID: ...,
clientSecret: ...,
callbackURL: ...,
scope: 'user:email',
},
...
);
Source
If you are using passport-github2 Strategy:
You should pass scope as an array, in github-passport2 Strategy.
passport.use(new GitHubStrategy({
clientID: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
scope: ['user:email'],
callbackURL: process.env.GITHUB_CALLBACK_URL
},
...
);
Source
Most authentication services have the concept of scopes--you can only get certain personal info if the user agrees to let you have it. For GitHub, see https://developer.github.com/v3/oauth/#scopes.
Basically, the scope(s) that you want access to must be passed along with the authentication request. I'm not sure how that happens with passport-github, but maybe there is another way to do it that sends the scope you are looking for.
If you really don't need the email address and you just wanted it for uniqueness, then don't ask for it--users will see what scope(s) you are requesting and if you ask for too many they may choose to not let your app authenticate. The user ID will be unique across GitHub, but may not be unique across all identity providers (if you eventually use more than just GitHub) so if you need a unique ID you should somehow combine/hash the provider and the user ID so you it is unique across all providers.
GitHub users can configure in their GitHub profile (Personal settings/Profile) a "Public email".
If they don't have selected a public email address, you won't receive any user email from GitHub.
The GitHub ID will be (probably) unique and permanent. But I suggest you to double check GitHub policies.

Express Passport.js Success redirect doesn't load page, request keeps pending

I am trying to do a basic username/password authentication using passport.js and passport local.
While failureRedirect does exactly what it is supposed to do, (redirects to a specified page), successRedirect keeps pending with the request for its specified page, and after some time, it returns empty response.
http://www.deviantpics.com/VdG
As you can see in this picture, when it is requesting dashboard, it says that its size is 0B, but when I go on that dashboard without redirecting it says it has 1.6B.
I have looked all over Stackoverflow, and I couldn't find an answer that would help me.
Could you please check my code and suggest something before I go berserk?
This is passport load code
//set expression
var expressSession = require('express-session');
app.use(expressSession({
secret: credentials.session.secret
}));
//set passport
var passport = require('passport');
var localStrategy = require('./strategies/auth/local.js');
passport.use('local', localStrategy);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.use(passport.initialize());
app.use(passport.session());
routes.js
module.exports = function(app) {
//main
app.get('/', main.home);
app.get('/login', main.login);
app.get('/signup', main.signup);
app.post('/login', auth.loginLocal);
app.post('/signup', main.checkSignup);
//user
app.get('/user/dashboard', user.dashboard);
app.get('/user/addmemory', user.addMemory);
app.get('/user/memory', user.memory);
login function
exports.loginLocal = passport.authenticate('local', {
successRedirect: '/user/dashboard',
failureRedirect: '/login'
});
local strategy
var localAuthStrategy = new LocalStrategy(function(username, password, done) {
User.findOne({
username: username
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Incorrect username'
});
}
if (!user.validPassword(password)) {
return done(null, false, {
message: 'Incorrect password'
});
}
return done(null, user);
});
});
dashboard function
exports.dashboard = function(req, res) {
res.render('user/dashboard', {
layout: 'user'
});
};
I found an answer to my question, the problem was that the User model was not defined in the script where serializeUser and deserializeUser were defined.
I could not figure out what was going on, because I did not define any action in catch all handler, so a thing to remember, make sure to have catch all handler defined to know what is happening
app.use(function(err, req, res, next) {
console.log(err);
});
I was facing the same problem as your a few days back and what I found was that I forgot to put parenthesis at the end of the serializeUser and deserializeUser functions.
I was actually using the passport-local-mongoose package for the respective functions. But it must be noted that in app.use() the functions are called and executed for all the template files so, we do use parenthesis with the names of the functions.

req.session.passport is empty: req.user undefined

I've asked a similar question before, but I noticed it was in the Javascript section.
I have more specific ideas of what might be going wrong now, as well.
Basically, req.session.passport is empty in my logs. Whenever I start navigating around my site, req.user becomes undefined because the session doesn't have Passport's logged in user anymore.
I would like to know if anyone knows how to solve this? Maybe it's just an error in the configuration of Passport, or the entire Express setup?
App.js:
var express = require("express"),
bodyParser = require("body-parser"),
mongodb = require("mongodb"),
mongoose = require("mongoose"),
uriUtil = require("mongodb-uri"),
morgan = require("morgan"),
session = require("express-session"),
passport = require("passport"),
flash = require("connect-flash"),
ip = "hidden",
port = process.env.PORT || 80
var app = express()
app.disable("x-powered-by")
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(morgan("dev")); // log every request to the console
// required for passport
app.use(session({
secret: "hidden",
key: 'asdasdasd',
cookie: { maxAge: 60000, secure: false },
resave: true,
saveUninitialized: false
})); // 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.set("view engine", "jade")
app.use(express.static(__dirname + "/views"))
require("./includes/passport")(passport)
require("./includes/subject")
require("./includes/user")
Passport.js:
var LocalStrategy = require("passport-local").Strategy,
User = require("./user"),
bCrypt = require('bcrypt-nodejs')
module.exports = function(passport) {
// 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('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({ "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("message", "Dit e-mail-adres is al bezet"));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.email = email;
newUser.password = createHash(password);
newUser.firstname = req.param('firstname');
newUser.lastname = req.param('surname');
newUser.year = parseInt(req.param('year'));
newUser.study = req.param('study');
newUser.courses = req.param('courses');
newUser.phone = req.param('phone');
newUser.availability = req.param('availability');
newUser.description = req.param('descText');
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// 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("login", 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) { // callback with email and password from our form
// 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({ "email" : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user) {
console.log('No user found with email ' + email)
return done(null, false, req.flash('message', 'Gebruiker niet gevonden')); // req.flash is the way to set flashdata using connect-flash
}
if (!isValidPassword(user, password)){
console.log('Incorrect Password');
return done(null, false, req.flash('message', 'Onjuist wachtwoord')); // redirect back to login page
}
// all is well, return successful user
return done(null, user);
});
}));
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
}
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
}
};
The routes:
api.post("/signup", passport.authenticate("signup", {
successRedirect: "/profile",
failureRedirect: "/",
failureFlash: true
}))
api.post("/login", passport.authenticate("login", {
successRedirect: "/profile",
failureRedirect: "/login"//,
failureFlash: true
}))
router.get("/", function(req, res) {
// serve index.html
res.render("index", {
title: 'Home',
user: req.user,
message: req.flash("message")
})
})
It works on the page that is accessed directly after logging in, which I control as follows:
router.get("/profile", isLoggedIn, function(req, res) {
res.render("profile", {
title: 'Gebruikersprofiel van ' + req.user.firstname + " " + req.user.lastname,
user: req.user // get the user out of session and pass to template
})
})
function isLoggedIn(req, res, next) {
console.log(req.session)
// 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("/login")
}
So far, I've tried adding middleware to add req.user to req.session, and doing the same thing in the login POST. Also I've tried changing the order in which I initialize the middleware in app.js. I am using the new express-session version, without CookieParser, as I read that CookieParser is no longer needed.
If anyone can help me in any way, it would be much appreciated! I've been stuck for a while (as have others).
The problem was not anything I did wrong in setting up the session, or Passport in general, but rather in my links.
I read somewhere that someone was accidentally working in multiple domains (his platform was apparently multi-server), and that made me look through my links this morning.
Apparently, I was linking to my website with www. prefixed, but the session was initialized where there was no www. in front of the URL. I saw this in the cookies.
The solution was, therefore, to link through the website consistently, either having www. prefixed everywhere or nowhere.

How to get data like email id, name from google using passport.js?

I am new to node.js environment and I am using passport.js for the authentication purpose.
I know how to authenticate using passport-google but I don't know how to get the data like email id, name, photo from the authenticated google account to the html form.
The following one is the server.js
..
var passport = require('passport')
..
app.get('/auth/google', passport.authenticate('google'));
app.get('/auth/google/return', passport.authenticate('google', { successRedirect: '/',
failureRedirect: '/login' }));
And the request.js file is
var passport = require('passport');
var GoogleStrategy = require('passport-google').Strategy;
passport.use(new GoogleStrategy({
returnURL: 'http://localhost:9000/profilepage.html',
realm: 'http://localhost:9000'
},
function(identifier, profile, done) {
User.findOrCreate({ openId: identifier }, function(err, user) {
done(err, user);
});
}
));
The profile data will be populated into the second argument (named profile) of callback function of GoogleStrategy. Take a look at this code example: https://github.com/jaredhanson/passport-google/blob/master/examples/signon/app.js
You can access user profile information like this:
function(identifier, profile, done) {
var userData = {identifier: identifier};
// append more data if needed
userData.email = profile.emails[0];
userData.displayName = profile.displayName;
userData.fullName = profile.familyName + " " + profile.givenName;
// id is optional
if (profile.id) {
userData.id = profile.id;
}
return done(null, userData);
});

Categories