I am trying to implement a passport oAuth login and signup API that will save a user to MongoDB on signup and login to an existing user.. I used my google mail accounts(3 of them) for testing but for some reason, it only signup and login to only one of my mail and then sends an error on an attempt to signup the other accounts. below is the passport code and controller code
controller code
async function ssoLogin(req, res, next){
// declare token;
let token;
// declare rider with sso login
let riderSSO;
try{
const { _raw, _json, ...userProfile } = req.user;
console.log(userProfile)
//validate sso details that will be added into model
const { error } = ssovalidateRider({
email: userProfile.emails[0].value.toLowerCase().trim(),
firstName: userProfile.name.familyName,
lastName: userProfile.name.givenName,
googleId: userProfile.id
});
if (error)
return res.status(400).json({
error: error.details[0].message,
});
// check if a user is already existing...
riderSSO= await RiderModel.findOne({googleId: userProfile.id});
if(riderSSO){
// create a Token
token= riderSSO.generateAuthToken(riderSSO._id, riderSSO.email)
delete riderSSO['__v'];
}else{
// Register new user here
riderSSO = await RiderModel.create({
// email: _json.email.toLowerCase().trim(),
email: userProfile.emails[0].value.toLowerCase().trim(),
googleId: userProfile.id,
firstName: userProfile.name.familyName,
lastName: userProfile.name.givenName
});
// create a Token
token= riderSSO.generateAuthToken(riderSSO._id, riderSSO.email)
delete riderSSO['__v'];
}
res.status(201).json({
status: 'success',
data: req.user,
token,
data: riderSSO
});
}catch(err){
console.log(err)
res.status(400).json({
sucess:'fail',
message: `unable to login or signup ${err}`,
});
}
}
passport config code:
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_1_ID,
clientSecret: process.env.CLIENT_1_SECRET,
callbackURL: "http://localhost:4000/api/v1/rider/google/callback",
proxy: true
}, (accessToken, refreshToken, profile, done) => {
console.log(accessToken);
return done(null, profile)
}));
error:
TypeError: Cannot read property '1' of null
at model.mongodbErrorHandler (C:\Users\peter\Desktop\driveme-backend-master\node_modules\mongoose-mongodb-errors\lib\plugin.js:19:49)
at callMiddlewareFunction (C:\Users\peter\Desktop\driveme-backend-master\node_modules\kareem\index.js:482:23)
at next (C:\Users\peter\Desktop\driveme-backend-master\node_modules\kareem\index.js:163:9)
at Kareem.execPost (C:\Users\peter\Desktop\driveme-backend-master\node_modules\kareem\index.js:217:3)
at _handleWrapError (C:\Users\peter\Desktop\driveme-backend-master\node_modules\kareem\index.js:245:21)
at _cb (C:\Users\peter\Desktop\driveme-backend-master\node_modules\kareem\index.js:304:16)
at C:\Users\peter\Desktop\driveme-backend-master\node_modules\mongoose\lib\model.js:341:9
at C:\Users\peter\Desktop\driveme-backend-master\node_modules\kareem\index.js:135:16
at processTicksAndRejections (internal/process/task_queues.js:79:11)
Related
I am trying to create a React Native app in which I am using an Express server with Passport.JS to act as the login/authentication server.
My current idea for logging in is this:
Open browser tab with login page
Login with Google / Facebook
Send accessToken and refreshToken back to React Native page via deep linking
Use accessToken to authenticate API requests to server (what I am having issues with)
Google Strategy:
passport.use(
new GoogleStrategy(
google,
async (accessToken, refreshToken, profile, done) => {
console.log(accessToken, refreshToken);
User.findOne()
.lean()
.exec({ googleID: profile.id }, async (err: any, user: UserModel) => {
if (err) {
console.log(err);
done(err, undefined);
return;
}
if (!user) {
let username =
profile?.emails?.at(0)?.value.split("#")[0] || profile.id;
username = await checkUsername(username, profile);
const newUser = new User({
googleID: profile.id,
username: username,
profileImage: profile?.photos?.at(0)?.value,
dateCreated: new Date(),
});
newUser
.save()
.lean()
.exec((err: any, createdUser: UserModel) => {
if (err) {
console.log(err);
done(err, undefined);
return;
}
createdUser.accessToken = accessToken;
createdUser.refreshToken = refreshToken;
done(null, createdUser);
});
return;
}
user.accessToken = accessToken;
user.refreshToken = refreshToken;
done(null, user);
});
}
)
);
Login Routes:
app.get(
"/user/login/google",
passport.authenticate("google", {
scope: ["profile", "email"],
prompt: "select_account",
accessType: "offline",
})
);
app.get(
"/user/login/google/callback",
passport.authenticate("google", {
failureRedirect: "/auth/google",
}),
(req, res) => {
const user = req.user as UserModel;
console.log(user);
res.redirect(
`myapp://login?id=${user?._id}&accessToken=${user?.accessToken}&refreshToken=${user?.refreshToken}`
);
}
);
Can I use what I have here to send what I have as the accessToken as a Bearer and authenticate the request? Or if this is not possible what is the best way to achieve this?
From my understanding when using Passport in a React website cookies are saved and used for authorization, however as I am sending this information to React Native this method isn't working.
I have tried using passport.authenticate("google") to authenticate the request by using both the Bearer token and sending access_token in the request, but neither seem to work
I am attempting to use Passport.js to authorize Google OAuth2 on Node.js. I have tried all week to make it work and have no idea why it isn't, so am now resorting to stack for some potential help. I have tried all solutions to similar problems available on forums online.
Each time it sends the request it returns TokenError: Bad Request, however, it is able to console.log the required data, so this to me demonstrates that the token was in fact successful. I cannot explain why this is occurring.
I have tried being more specific in callback request e.g http://localhost:3000/auth/google/redirect.
I have tried every other type of Oauth type google has Node server, web application, html ect.
I have tried different ports.
AUTH ROUTES
const router = require('express').Router();
const passport = require('passport');
// auth login
router.get('/login', (req, res) => {
res.render('login', { user: req.user });
});
// auth logout
router.get('/logout', (req, res) => {
// handle with passport
res.send('logging out');
});
// auth with google+
router.get('/google', passport.authenticate('google', {
scope: ['profile']
}));
// callback route for google to redirect to
// hand control to passport to use code to grab profile info
router.get('/google/redirect', passport.authenticate('google'),
(req,
res) => {
res.send('you reached the redirect URI');
});
module.exports = router;
PASSPORT_SETUP
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const keys = require('./keys');
passport.use(
new GoogleStrategy({
// options for google strategy
clientID: keys.google.clientID,
clientSecret: keys.google.clientSecret,
callbackURL: '/auth/google/redirect'
}, (accessToken, refreshToken, profile, done) => {
// passport callback function
console.log('passport callback function fired:');
console.log(profile);
})
);
When submitted the process progresses through SignIn page, delivers desired result the console.log and then just sits for about 1 minute awaiting localhost.
As you can see the very thing it is trying to retrieve is already in the console.
It then progresses to throw and Error:
Sorry for the late reply, dug up some old code this is the point where it was marked as 'All auth methods functioning'. As stated by Aritra Chakraborty in the comments, "done" method was not being called. See the following implementation with Nedb.
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const Datastore = require('nedb');
const database = new Datastore('database.db');
database.loadDatabase();
passport.serializeUser((user, done) => {
done(null, user.googleId || user.id);
});
passport.deserializeUser((googleId, done) => {
database.findOne({ googleId : googleId }, (err, user) => {
done(null, user);
});
});
var strategy = new GoogleStrategy({
// options for google strategy
clientID: keys.google.clientID,
clientSecret: keys.google.clientSecret,
callbackURL: '/auth/google/redirect'
}, (accessToken, refreshToken, object0, profile, done) => {
// check if user already exists in our own db
database.findOne({ googleId: profile.id }, (err, currentUser) => {
if (currentUser !== null) {
done(null, currentUser);
} else {
var d = new Date();
var n = d.getTime();
var duoID = uuidv1();
var User = {
duoVocalID: duoID,
googleId: profile.id,
username: profile.displayName,
thumbnail: profile._json.image.url,
oscope: object0.scope,
oaccess_token: object0.access_token,
otoken_type: object0.token_type,
oid_token: object0.id_token,
oexpires_in: object0.expires_in,
oemails: profile.emails,
olanguage: profile._json.language,
oname: profile.name,
TimeOfLastLogon: n,
RefreshToken: refreshToken
};
database.insert(User, (err, newUser) => { });
var newUser = User;
done(null, newUser);
}
});
});
passport.use(strategy);
// auth with google+
app.get('/auth/google', passport.authenticate('google', {
scope: ['profile', 'email', 'https://www.googleapis.com/auth/spreadsheets'],
accessType: 'offline',
approvalPrompt: 'force'
}));
// callback route for google to redirect to
// hand control to passport to use code to grab profile info
app.get('/auth/google/redirect', passport.authenticate('google'), async (req, res) => {
var userString = JSON.stringify(req.user)
jwt.sign({userString}, 'secretKey', { expiresIn: '365d' }, (err, token) => {
res.send("<script>localStorage.setItem('token', '"+token+"'); window.close(); window.opener.document.getElementById('modal-toggle').checked = false;</script>");
});
});
I am using Sails.js and trying to use Passport.js with a REST API.
But I am facing the following error when I try to call my login function in my controller:
/Users/Michael/Development/DictationProject/sails/20151010/dictee/node_modules/passport/lib/http/request.js:44
if (!this._passport) { throw new Error('passport.initialize() middleware not in use'); }
^
Error: passport.initialize() middleware not in use
at IncomingMessage.req.login.req.logIn (/Users/Michael/Development/DictationProject/sails/20151010/dictee/node_modules/passport/lib/http/request.js:44:34)
at /Users/Michael/Development/DictationProject/sails/20151010/dictee/api/controllers/AuthController.js:20:17
at Strategy.strategy.success (/Users/Michael/Development/DictationProject/sails/20151010/dictee/node_modules/passport/lib/middleware/authenticate.js:194:18)
at verified (/Users/Michael/Development/DictationProject/sails/20151010/dictee/node_modules/passport-local/lib/strategy.js:83:10)
at /Users/Michael/Development/DictationProject/sails/20151010/dictee/config/passport.js:53:18
My config/http.js file is configured as below (Session is loaded before passportInit and passportSession):
passportInit : require('passport').initialize(),
passportSession : require('passport').session(),
flash : require('connect-flash'),
order: [
'startRequestTimer',
'cookieParser',
'session',
'passportInit',
'passportSession',
'myRequestLogger',
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'$custom',
'flash',
'router',
'www',
'favicon',
'404',
'500'
],
Don't understand what is wrong...
EDIT:
It seems to be coming from passport.use() in config/passport.js :
passport.use('login', new LocalStrategy({
passReqToCallback : true,
usernameField: 'email',
passwordField: 'password'
},
function(req, email, password, done) {
console.log('In passport.use login');
// check in mongo if a user with email exists or not
User.findOne({ 'email' : email }, function (err, user) {
// In case of any error, return using the done method
if (err) {
console.log('Error passport.use login');
return done(err);
}
// Username does not exist, log error & redirect back
if (!user) {
console.log('User Not Found with email '+email);
return done(null, false, req.flash('message', 'User Not found.'));
}
console.log('One user matching this email address found');
// User exists but wrong password, log the error
bcrypt.compare(password, user.password, function (err, res) {
if (!res) {
console.log('Invalid Password');
return done(null, false, req.flash('message', 'Invalid Password'));
}
// User and password both match, return user from
// done method which will be treated like success
console.log('One user matching this email address and password found');
var returnUser = {
name: user.name,
email: user.email,
createdAt: user.createdAt,
id: user.id
};
console.log('Returning User: ' + returnUser);
return done(null, returnUser,
req.flash('message', 'Logged In Successfully')
);
});
});
}
));
Following the recommendations from Sails.js creator on passport: https://github.com/balderdashy/sails/pull/1224
Issue is solved by putting the Passport middleware in the config/policies.js file:
var passport = require('passport');
module.exports.policies = {
'*': [
// Initialize Passport
passport.initialize(),
// Use Passport's built-in sessions
passport.session()
]
}
I am using Sails.js and tryong to use Passport.js with a REST API
You do it wrong. You don't need to call initialize() and session() methods. If you really have REST API then it stateless and doesn't store information about users in session.
My middleware configuration looks like this and everything works great with passport and many other strategies like passport-facebook-token and passport-google-plus-token.
order: [
'compress',
'keepAlive',
'bodyParser',
'$custom',
'router',
'404',
'500'
]
I am using passport GoogleStrategy to authenticate users, but i am getting below error. Can you please help me ?
Code
passport.use(new GoogleOAuth2Strategy({
clientID : configAuth.googleAuth.clientID,
clientSecret: configAuth.googleAuth.clientSecret,
callbackURL: configAuth.googleAuth.callbackURL,
scope: ['profile', 'email', 'openid'],
passReqToCallback : true
},
function(token, refreshToken, profile, done) {
// User.findOne won't fire until we have all our data back from Google
process.nextTick(function() {
console.log(profile.id);
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;
console.log(profile.id);
console.log(token);
console.log(profile.displayName);
console.log(profile.emails[0].value);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
Error Log
500 failed to obtain access token (Error: connect ECONNREFUSED) at
D:\Chandrasekhar\NodeJs_Workspace\SkillsetMgmtNode\node_modules\passport-google-oauth\node_modules\passport-oauth\lib\passport-oauth\strategies\oauth2.js:125:38 at
D:\Chandrasekhar\NodeJs_Workspace\SkillsetMgmtNode\node_modules\passport-google-oauth\node_modules\passport-oauth\node_modules\oauth\lib\oauth2.js:177:18
at ClientRequest.
(D:\Chandrasekhar\NodeJs_Workspace\SkillsetMgmtNode\node_modules
\passport-google-oauth\node_modules\passport-oauth\node_modules\oauth\lib\oauth2.js:148:5)
I too was getting the same error . For me the error was because i was behind a proxy . When run without proxy the code worked fine . So try this once .
I'm attempting to authenticate a user using Box.com OAuth2.0. I make the initial call and login which redirects to my callback url with the authorization code. At this point my server handles the callback using passport but for some reason it returns a 302 and redirects to the beginning of the oauth authentication process.
//box authentication routes
app.get('/api/box', passport.authorize('box'));
// the callback after box has authorized the user
app.get('/api/box/callback', passport.authorize('box', {
successRedirect: '/',
failureRedirect: '/login'
})
);
I verified that my route is being called by using my own handler and the request data seems to be correct. Box returns a 200 and the url contains the authorization code.
app.get('/api/box/callback', function(req, res) {
console.log('auth called')
});
This is my passport strategy:
passport.use(new BoxStrategy({
clientID: config.box.clientID,
clientSecret: config.box.clientSecret,
callbackURL: config.box.callbackURL,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function() {
if(!req.user) {
// try to find the user based on their google id
User.findOne({ 'box.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
// if a user is found, log them in
return done(null, user);
} else {
// if the user isnt in our database, create a new user
var newUser = new User();
// set all of the relevant information
newUser.box.id = profile.id;
newUser.box.accessToken = accessToken;
newUser.box.refreshToken = refreshToken;
newUser.box.name = profile.name;
newUser.box.email = profile.login;
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
} else {
// user already exists and is logged in, we have to link accounts
var user = req.user;
// update the current users box credentials
user.box.id = profile.id;
user.box.accessToken = accessToken;
user.box.refreshToken = refreshToken;
user.box.name = profile.name;
user.box.email = profile.login;
// save the user
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
}
));
Would appreciate any insight as to what might be causing this redirect behavior.
It ended up being an instance of PeerServer that was somehow causing the redirect.