node.js Googe Authentication callback error - javascript

I'm trying to set up Googe Authentication to a website running off node.js, passport.js, express & mongodb, largely based off this example. I have managed to get local authentication working but when trying to get Google Authentication working, I'm getting a TypeError: OAuth2Strategy requires a verify callback error when trying to initialise the server.
The authentication strategy for Google is held in /config/passport.js, shown below:
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy();
var User = require('../models/user');
var configAuth = require('./auth');
module.exports = function(passport) {
// serialize the user session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// deserialize the user session
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =================GOOGLE=======================
var strategyOptions = {
clientID : configAuth.googleAuth.clientID,
clientSecret : configAuth.googleAuth.clientSecret,
callbackURL : configAuth.googleAuth.callbackURL,
};
var verifyCallback = function(token, refreshToken, profile, done) {
process.nextTick(function() {
User.findOne({ 'google.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, user);
} else {
var newUser = new User();
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value;
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
};
passport.use(new GoogleStrategy(strategyOptions, verifyCallback));
};
My app.js looks as follows (with the invocation of passport.js bolded):
// set up ================================================================
var express = require('express');
var app = express()
var path = require('path');
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var configDB = require('./config/database.js');
// config ================================================================
mongoose.connect(configDB.url);
require('./config/passport')(passport);
//set up express application
app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser());
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(session({ secret: 'what a long string' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(express.static(path.join(__dirname, 'public')));
// routes ================================================================
require('./routes/index.js')(app, passport);
// launch ================================================================
//app.listen(port);
module.exports = app;
I can't tell what is going wrong here, because as far as I can see verifyCallback is being supplied in the passport.use() function. I've spent the last day Googling around and searching through StackOverflow but haven't found a fix that works yet.
Apologies if this is a really obvious error, I'm new to the whole node ecosystem and web design in general. Happy to provide more information if that is helpful.

You have done it well.The issue is with getting google strategy.
Change this line
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy();
To below mentioned one
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
You can see the working example here for any other issue.
For Reference: https://github.com/Khushbu-2112/OAuth-google-example

Related

node.js/express.js connection pool Cannot read properties of undefined (reading 'getConnection')

So I created a new node.js project and used express.js to build the basics to start of. Now I want to do a simple get call to get data from my database through a connection pool. When I do the call in app.js there is no problem, but when trying to do the same call from my users.js file in a get route it throws 'connection pool Cannot read properties of undefined (reading 'getConnection')'.
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mysql = require('mysql');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// establish connection to database
var conpool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: '****',
password: '****',
database: 'db_name'
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = {app, conpool};
user.js (located in routes directory which is on the same hierarchy level as app.js)
var express = require('express');
var router = express.Router();
var db = require('../app').conpool;
/* GET users listing. */
router.get('/get', function (req, res, next) {
db.getConnection((err, connection) => {
if (err) throw err;
var sql = null;
if (req.query.name) {
sql = 'SELECT * FROM users WHERE name = ' + sql.escape(req.query.name);
} else {
sql = 'SELECT * FROM users';
}
connection.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
});
});
});
module.exports = router;
Does anyone have any idea why this is happening? Is there something wrong with how I am using module.exports? Is it a problem of trying to call a function on a reference instead of the original pool object?
It seems Evert's solution was the one I was looking for. I'll describe the changes I made compared to the files shown in my question to show how it solved it.
I made a completely new file database.js (on the same level of hierarchy as app.js):
var mysql = require('mysql');
var conpool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: '****',
password: '****',
database: 'db_name'
});
module.exports = conpool;
and deleted all these lines of code from app.js
in user.js only one line changed:
var db = require('../app.js')
to
var db = require('../database');

TypeError: req.flash is not a function (NodeJs)

Working with Registration in a Site. For the register Form,Validation is done using mongoose models and trying to Use Flash to display the error message in the Form.
But struct at this error
TypeError: res.flash is not a function
at /home/work/first-node-app/firstnode/routes/index.js:35:11
My Code snippets Follows below
App.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mongoose = require('mongoose');
var passport = require('passport');
var session = require('express-session');
var flash = require('connect-flash');
var indexRouter = require('./routes/index');
var commonKeys = require('./config/config');
var app = express();
//connect mongoDb
mongoose.connect('mongodb://localhost:27017/db', { useNewUrlParser: true });
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// required for passport session
app.use(session({
secret: 'secrettexthere',
saveUninitialized: true,
resave: true,
// using store session on MongoDB using express-session + connect
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use('/', indexRouter);
module.exports = app;
Index.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/user-model');
var Local = require('../config/passport-local');
router.get('/register', function(req, res){
res.render('public/register',{title:'Register'});
});
router.post('/register', function(req,res,next){
User.create({name:req.body.name, password:req.body.password, email : req.body.email}, function(err, user){
if (err) {
console.log('Error Inserting New Data');
if (err.name == 'ValidationError') {
for (field in err.errors) {
res.flash(field, err.errors[field].message);
}
res.render('public/register');
}
}
if(user) {
res.send('user registered');
}
})
});
module.exports = router;
Can anyone point out the error in this code snippets, as am new to Nodejs and Trying to work out the Form validation. The validation Works fine and the console displays the error but i can't pass that using flash. Can anyone Help me? And its much appreciated if you confirm my approach to code Nodejs is in correct way.
Use req.flash() in place of res.flash. Refer here for more clarification.

Session Node.js + Passport.js + Redis, Store session by user.id

When a user logs in a session is created for him, but if he were to go to another computer and login a 2nd session would be created for his account. I would like to make it so that a user could not have more then one valid session. Is there anyway to store sessions in redis by user.steamId so that his first session becomes invalid?
Any help would be great thanks!
app.js
var express = require('express'),
http = require('http');
var app = express();
var cookie = require('cookie');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var redis = require('redis');
var client = redis.createClient();
var session = require('express-session');
var redisStore = require('connect-redis')(session);
io.set('transports', ['websocket']);
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
const fs = require('fs');
require('./config/passport')(passport);
var sessionMiddleware = session({
store:new redisStore({host:'localhost',port:6379,client:client}),
secret:'secretTextchange',
saveUninitialized:false,
resave:false
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(sessionMiddleware);
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
require('./routes/routes')(app,passport,client);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
io.use(function(socket, next) {
sessionMiddleware(socket.request, {}, next);
});
io.sockets.on('connection', function (socket) {
console.log("verified");
socket.on('message',function(msg){
io.sockets.emit('rmessage', {
name:socket.request.session.passport.user.name,
avatarUrl:socket.request.session.passport.user.avatarUrl,
message:msg
});
});
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
server.listen(3000);
module.exports = app;
passport.js
var OpenIDStrategy = require('passport-openid').Strategy;
var auth = require('./auth');
var steam = require('./steam');
var s = new steam({
apiKey: auth.Steam.apiKey,
format:'json'
})
module.exports = function(passport){
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null,user);
});
var SteamStrategy = new OpenIDStrategy({
// OpenID provider configuration
providerURL: auth.Steam.providerUrl,
stateless: auth.Steam.stateless,
// How the OpenID provider should return the client to us
returnURL: auth.Steam.returnUrl,
realm: auth.Steam.realm,
},
function(identifier, done) {
process.nextTick(function () {
console.log("passport-"+identifier);
s.getPlayerSummaries({
steamids:identifier.match(/\d+$/)[0],
callback:function(err,data){
var user = {
steamid:identifier.match(/\d+$/)[0],
avatarUrl: data.response.players[0].avatar,
name:data.response.players[0].personaname
};
return done(null, user);
}
});
// In case of an error, we invoke done(err).
// If we cannot find or don't like the login attempt, we invoke
// done(null, false).
// If everything went fine, we invoke done(null, user).
});
});
passport.use(SteamStrategy);
}
routes.js
module.exports = function(app,passport,client){
app.get('/', function (req,res) {
res.render('index.ejs',{
user: req.user,
title:"yo"});
});
app.get('/auth',passport.authenticate('openid'));
app.get('/auth/return',passport.authenticate('openid'),function(req,res){
if (req.user) {
res.redirect('/');
} else {
res.redirect('/');
}
});
}
Could you use this: https://www.npmjs.com/package/redis-sessions ?
There's a method called soid which gets all sessions of a single id. You could query user's id as they log in. Then get all the sessions from that id. If soid returns empty you can safely assume the user had no sessions. If it returns with things inside it, then the user has sessions.
This is my best attempt right now.
Good luck.

Getting the current user in express.js, while using socket.io?

I'm using the express framework, and part of my web app uses socket.io to enable real-time chat. I need to get the current user's username, and create a room with him in it. The problem is I can't find a way to get the user info when socket.on('connection') is called. Here's the relevant code I have so far :
var express = require('express');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var session = require('express-session');
var http = require('http');
var routes = require('./routes/index');
var app = express();
var server = http.createServer(app);
var io = require('socket.io')(server);
server.listen(4000);
app.use(session({secret : 'anything',
saveUninitialized: true,
resave: true}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect('mongodb://localhost/my_db');
var Schema = mongoose.Schema;
var UserDetail = new Schema({
username: String,
password: String
}, {
collection: 'users'
});
var UserDetails = mongoose.model('users', UserDetail);
app.use('/', routes);
app.use('/users', users);
app.post('/login',
passport.authenticate('local', {
successRedirect: '/loginSuccess',
failureRedirect: '/loginFailure',
})
);
io.on('connection', function(socket) {
console.log('socket stuff');
var sessionStore = session;
var sessionId = socket.handshake.sessionId;
sessionStore.get(sessionId, function(err, session) {
if(!err) {
console.log('no error');
if(session.passport.user) {
console.log('This is the users email address %s', session.passport.user);
}
}
});
socket.emit('newMessage', {content : 'Chat message content'});
});
The last function is where I'm having trouble. When a user requests a page, I can just find their username by req.user, but I have no idea how to do it when I don't have req. The code I have for sessions in io.on('connection') does not work at all, and just throws errors, figured I'd keep it in to show what I've tried so far.
This has been asked a few times but the older answers I found do not work anymore. The answer lies in parsing socket.handshake.headers.cookie but this is hacky and will depend on the internals of express-session.
Anyways, this should work for now with Express 4 and socket.io 1.1:
var express = require('express'),
session = require('express-session'),
cookie = require('cookie'),
signature = require('cookie-signature');
var app = express(),
store = new session.MemoryStore(),
secret = 'session-secret-key',
name = 'connect.sid';
app.use(session({
name: name,
secret: secret,
store: store,
resave: true,
saveUninitialized: true
}));
var server = require('http').createServer(app),
io = require('socket.io')(server);
io.on('connection', function(socket) {
if (socket.handshake && socket.handshake.headers && socket.handshake.headers.cookie) {
var raw = cookie.parse(socket.handshake.headers.cookie)[name];
if (raw) {
// The cookie set by express-session begins with s: which indicates it
// is a signed cookie. Remove the two characters before unsigning.
socket.sessionId = signature.unsign(raw.slice(2), secret) || undefined;
}
}
if (socket.sessionId) {
store.get(socket.sessionId, function(err, session) {
console.log(session);
});
}
});

Passport.js Module, undefined callbackURL

After setting up the Drupal as this guide says: Drupal-passport I created a simple simple node app to test how it works.
It doesn't, I get the InternalOAuthError: Failed to obtain request token error.
Going through the strategy.js, I saw that my callbackURL is logging out undefined not exactly sure why. The callbackURL is set in my Drupal app
Also preforming a curl -i -XPOST http://extranet.local/rest/system/connect/ gives me exactly what I need
Here is my node.js code (keep in mind this is just supposed to test the drupal set up).
var express = require('express');
var passport = require('passport');
var dStrategy = require('passport-drupal').DrupalStrategy;
var passportDrupal = require('passport-drupal');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser')
var session = require('express-session');
var http = require('http');
var app = express();
var server = http.createServer(app);
app.use(cookieParser());
app.use(bodyParser());
app.use(session({ secret: 'SECRET' }));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new dStrategy({
consumerKey: "emDVp7P2LZFLPcN3cNCjLmrjrhQLnNv6",
consumerSecret: "mkbc3UYEuUQLNQRwLWo3B8zEk4ZrErKa",
providerURL: "http://extranet.local",
resourceEndpoint: "rest/system/connect", // <---- optional. Defaults to `rest/system/connect`
callbackURL: 'http://33.33.33.40:8888/auth/drupal/callback'
},
function(token, tokenSecret, profile, done) {
profile.oauth = { token: token, token_secret: tokenSecret };
done(null, profile);
}
));
app.get('/', function(req, res) {
res.writeHead(200);
res.end("This is root");
});
app.get('/auth/drupal',
passport.authenticate('drupal'),
function(req, res) {
// The request will be redirected to the Drupal website for
// authentication, so this function will not be called.
});
app.get('/auth/drupal/callback',
passport.authenticate('drupal', { failureRedirect: '/error' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/signedin');
});
app.get('/error', function(req, res) {
res.writeHead(200);
res.end("Could not sign in");
});
app.get('/signedin', function(req, res) {
res.writeHead(200);
res.end("signed in");
});
server.listen(8888, '33.33.33.40');
Any clues as to why or ideas are greatly appreciated
If you look into the strategy.js code of the library passport-drupal, you will see that the DrupalStrategy constructor does not expect a callbackURL property in the options parameter object and it also does not pass it further into the OAuthStrategy.
This is the code snippet that creates the parameter for the oauth strategy:
// Determine all necessary OAuth options
var oauthOptions = {
requestTokenURL: this._providerURL + '/oauth/request_token',
accessTokenURL: this._providerURL + '/oauth/access_token',
userAuthorizationURL: this._providerURL + '/oauth/authorize',
consumerKey: options.consumerKey,
consumerSecret: options.consumerSecret
};
OAuthStrategy.call(this, oauthOptions, verify);
It should be modified to pass the callbackURL, for example like this:
// Determine all necessary OAuth options
var oauthOptions = {
requestTokenURL: this._providerURL + '/oauth/request_token',
accessTokenURL: this._providerURL + '/oauth/access_token',
userAuthorizationURL: this._providerURL + '/oauth/authorize',
consumerKey: options.consumerKey,
consumerSecret: options.consumerSecret,
callbackURL: options.callbackURL// <==== THIS LINE WAS ADDED
};
OAuthStrategy.call(this, oauthOptions, verify);
I'm not sure that will solve your issue though. But I made a pull request

Categories

Resources