I am using LinkedIn OAuth and passport for my sign in. For whatever reason the first time I try to log in, it routes to homepage without logging in. The second time however, it logs in properly. What might be causing this problem? LinkedIn or passport?
This is the get path :
router.get('/auth/linkedin/callback', passport.authenticate('linkedin', {failureRedirect: '/', failureFlash:true}),
function (req, res, next) {
User.findOne({_id: req.user._id}, function (err, user) {
if (err) {
return next(err);
res.redirect("/")
}
user.last_login = moment();
user.save()
return res.redirect('/profile/' + user.username);
});
});
And then the passport linkedIn :
passport.use(new LinkedInStrategy({
clientID: config.linkedin.consumerKey,
clientSecret: config.linkedin.consumerSecret,
callbackURL: config.linkedin.callbackURL,
state: true,
scope: ['r_basicprofile', 'r_emailaddress']}, function (token, refreshToken, profile, done) {
...
Related
Here's the code i typed.
var passport = require("passport");
var GoogleStrategy = require("passport-google-oauth").OAuth2Strategy;
// 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: '28013134812-qc5lbogacg4cf42etiruqveskh8vaqgh.apps.googleusercontent.com',
clientSecret: 'secret! i can't type secret here',
callbackURL: "www.example.com.com/auth/google/callback",
},
function (accessToken, refreshToken, profile, done) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return done(err, 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"],
})
);
// 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(
"/auth/google/callback",
passport.authenticate("google", { failureRedirect: "/login" },
function (req, res) {
res.redirect("/");
})
);
ReferenceError: User is not defined
at Strategy._verify (C:\Users\hp\short.nner\server.js:64:7)
at C:\Users\hp\short.nner\node_modules\passport-oauth2\lib\strategy.js:202:24
at C:\Users\hp\short.nner\node_modules\passport-google-oauth20\lib\strategy.js:122:5
at passBackControl (C:\Users\hp\short.nner\node_modules\oauth\lib\oauth2.js:134:9)
at IncomingMessage. (C:\Users\hp\short.nner\node_modules\oauth\lib\oauth2.js:157:7)
at IncomingMessage.emit (node:events:341:22)
at endReadableNT (node:internal/streams/readable:1294:12)
at processTicksAndRejections (node:internal/process/task_queues:80:21)
I copied the above code from passport docs. Does anyone know why I am getting this error?
What actually is User here?
i think something's wrong with this code
function (accessToken, refreshToken, profile, done) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return done(err, user);
});
}
Just put correct callback URL here callbackURL: "http://localhost:3000.com/auth/google/callback", and define User. That's it
I'm trying to authenticate and authorize users with Passport.js using Google API. I have G Suite and all my users are part of a G Suite organization. I've set up a bunch of roles in G Suite to use with my custom app.
The authentication part is fine and works as intended. The problem is that I need to make a subsequent call to https://www.googleapis.com/admin/directory/v1/customer/customer/roleassignments with the userKey of the logged-in user to get all the assigments that this user has and I'm not sure what's the best way to do that.
This is what the relevant parts of my /login route look like now:
passport.use(
new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.BASE_URL + '/login/google/callback'
},
function (accessToken, refreshToken, profile, done) {
return done(null, profile)
})
)
router.get('/', function (req, res, next) {
// Render the login button
})
router.get('/google',
passport.authenticate('google', {
scope: [
'email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly'
]
})
)
router.get('/google/callback', function (req, res, next) {
passport.authenticate('google', function (err, user, info) {
if (err) { return next(err) }
if (!user) { return res.redirect('/login?error=no_user') }
req.login(user, function (err) {
if (err) { return next(err) }
const accessToken = req.user.accessToken
// Maybe do something here?
return res.redirect('/')
})
})(req, res, next)
})
I can store the accessToken to the user session when I get it and just make a callback using the token as a bearer token and this probably works fine, but is this really the way it's supposed to work? Does Passport.js provide some kind of mechanism to make the subsequent, authenticated calls easier?
After further investigations, I believe you're supposed to modify the Strategy callback if you have additional steps to take after the initial authentication.
So to get custom User Roles set up in G Suite Admin, you could do it like this using the external request library:
import request from 'request'
passport.use(
new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.BASE_URL + '/login/google/callback'
},
function (accessToken, refreshToken, profile, done) {
const url = 'https://www.googleapis.com/admin/directory/v1/customer/' +
process.env.GOOGLE_CUSTOMER_ID +
'/roleassignments' +
'?userKey=' +
profile.id
request.get(url, {
auth: {
bearer: accessToken
}
}, (error, response, body) => {
if (error) {
console.error(error)
return done(null, false, { message: 'Could not authenticate.' })
}
const items = JSON.parse(response.body).items
let role = null
const roles = items.map((value) => {
return value.roleId
})
if (roles.includes(process.env.GOOGLE_ROLE_ID_ADMIN)) {
role = 'ADMIN'
} else if (roles.includes(process.env.GOOGLE_ROLE_ID_OTHER)) {
role = 'OTHER'
} else {
return done(null, false, { message: 'No valid user role' })
}
console.log('User role is ' + role)
profile.role = role
return done(null, profile)
})
})
)
If you assign the acquired role to the profile, you can easily access it later with req.user.role.
I'm using passport-github for authenticating with GitHub, but every time a user logs in, the access token updates. Is that intended behaviour?
Strategy configuration and Express routing:
passport.use(new GithubStrategy({
clientID: process.env.IMPAKT_ID,
clientSecret: process.env.IMPAKT_SECRET,
callbackURL: process.env.IMPAKT_CALLBACK
}, function(accessToken, refreshToken, profile, cb) {
User.findOneAndUpdate({id: profile.id}, {accessToken, username: profile.username}, {upsert: true, new: true}, function(err, user) { // Update code, since access token changes.
return cb(err, user);
});
}
));
app.get("/auth", passport.authenticate('github', {scope: ['public_repo']}));
app.get("/auth/callback", passport.authenticate('github', { failureRedirect: '/auth' }), function(req, res) {
res.redirect('/');
});
I am implementing a Facebook authentication using Passport in node.js. I can get the users profile from Facebook successfully. The problem is, the code should redirect the user to the successRedirect: /profile but instead it always goes to /fbFailure. No matter what I tried, it always goes to the url : somesite.com:6161/fbFailure#=
Passport middleware code:
var FacebookStrategy = require('passport-facebook').Strategy;
var models = require('../models');
passport.use('facebook', new FacebookStrategy(
{
clientID: '1735552370024305', clientSecret: 'a004f1aee925b615022d7573984d5c26', callbackURL: "http://www.somesite.com:6161/facebookSuccess", profileFields: ['id', 'displayName', 'photos', 'emails'],
},
function(access_token, refreshToken, profile, done) {
console.log('profile', profile);
models.Member.findOne({ '__id' : profile.id }, function(err, user) {
if (err)
return done(err);
if(user){
return done(null, user);
}
done(null, user);
})
}
));
My Routes:
app.get('/facebook', passport.authenticate('facebook', { scope : 'email' }));
app.get('/facebookSuccess', passport.authenticate('facebook', {
successRedirect : '/profile',
failureRedirect : '/fbFailure'
}));
app.get('/profile', function(req, res, next) {
res.send('Successfully authenticated');
});
app.get('/fbFailure', function(req, res, next) {
res.send('Failed to authenticate');
});
Console Output:
json:
{ id: '10154130288931542',
name: ‘Tom Verra’,
picture: { data: [Object] },
email: ‘tom.vera#mysite.com' } }
GET /facebookSuccess?code=AQBzdIfKPQ..............YU6TvYuf......
Any help would be highly appreciated. Thanks in advance.
You could try redirecting using res.redirect('/profile');, just the way it is done in the passport-facebook readme on GitHub (https://github.com/jaredhanson/passport-facebook#authenticate-requests):
app.get('/facebookSuccess',
passport.authenticate('facebook', { failureRedirect: '/fbFailure' }),
function(req, res) {
res.redirect('/profile');
});
I have an existing user base, that I want to allow them to link with their Facebook/Twitter Accounts. Looks like I can use passportjs but am having difficulty,
Right now, a url pass in their user/pass, I do a local stragety, and look up the user. Then I want to perform an authorize I presume. I get the facebook promopts asking if I want to allow, and I hit the callback with the accessToken, but I have no way to tie that token to an existing user in my db as I see now way to get the request info.
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
Users.findOne({_id: user._id}, function(err, user) {
return done(err, user);
});
});
passport.use(new LocalStrategy({ passReqToCallback: true }, function(req, username, password, done) {
Users.findOne({_id: username}, function(err, user) {
return done(null, user);
});
}
));
passport.use(new FacebookStrategy({
clientID: 'xxxx',
clientSecret: 'xxxx',
callbackURL: "http://xxxx/facebook/callback",
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
// How would I get access to the user found in the LocalStrategy here so I can associate the accessToken to the user in the db?
console.log(accessToken);
console.log(refreshToken);
var err = null;
var user = {};
return done(err, user);
}
));
server.get('/facebook', passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function (req, res) {
if (req && req.user) {
passport.authorize('facebook', { scope: ['publish_actions','manage_pages'] })(req, res);
}
});
server.get('/facebook/callback',
passport.authorize('facebook', { failureRedirect: '/facebook/failure', successRedirect: '/facebook/success' }),
function(req, res) {
res.redirect('/');
}
);
Assuming that the user is already logged in with the local strategy, the user should be available on the request as req.user. You can then add the facebook credential information to the existing user object.
Check to see which URL you are redirecting to on your Facebook callback and make sure that you aren't generating different sessions between the time that you log in locally and the time that you are directed to your callback from Facebook.
I had a similar issue that was driving me crazy, and it's because my redirects were different.
For example, I was navigating to http://localhost:3000 in Chrome, logging in and req.user was being set correctly. On my Facebook dev settings, and Passport config, I was redirecting to http://hostname.local:3000/auth/facebook.
As long as your local login and redirect share the same session, then req.user should be available.