I am writing a code to add functionality of logging in with Google. I have written code but when a user log in with google, it only gives me id, name, fullname etc. It does not provide with user email address. Can any one help me to solve this? Following is my code
passport.use(new GoogleStrategy({
clientID: CLIENT_ID,
clientSecret: CLIENT_SECRET,
callbackURL: "http://localhost:8000/auth/google/notepad"
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
router.get('/auth/google', passport.authenticate('google',{scope: ['profile']}));
router.get('/auth/google/notepad',
passport.authenticate('google', { failureRedirect: '/' }),
async function(req, res) {
const token = await req.user.generateAuthToken();
res.cookie('authToken', token);
res.redirect('/')
});
You are missing the email scope. It’s a separate scope to their profile.
See the docs too if you want to know more: https://developers.google.com/identity/protocols/oauth2/openid-connect#scope-param
Related
I successfully got the user details but the email field is null.After some time got to know that I need to fetch it from "https://api.github.com/user/emails".I used axios and also provided accesstoken as header but it is giving me "▼♥��A�#►���\�%♥+=y��5"V↔ubWevW�迧F�¶◄t��☻�%)H�ɢ�k��♥葩$,�7↓�H�↔?��^Z�k�r���:��x�▬♣▬NP������҇�C�v�C▼o.�pK~☺" instead of emails.
passport.use(new GitHubStrategy({
clientID: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
callbackURL: "/callbackurl"
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate({ githubId: profile.id }, function (err, user){ //I am using mongoose-findorcreate npm
axios.get('https://api.github.com/user/emails', {
headers: {
"Authorization": "Bearer "+ accessToken,
}
}).then((res)=>{
console.log(res.data);
})
return done(err, user);
});
}
));
It's because you have not specified scope inside your strategy so Inside your github Strategy , also include scope key:
scope: ["user:email"],
As:
`new GitHubStrategy({
clientID: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
callbackURL: "/callbackurl",
scope: ["user:email"]
}`
I looked in several posts, but I cannot find something that meets my situation.
To login (or signup) with google, you have to go to mydomain.com/login/google
You then, well, login with google, and then the callback is handled on mydomain.com/auth/google
Here is the code responsible for this.
app.get('/login/google', passport.authenticate('google'));
app.get('/auth/google',
passport.authenticate('google', { failureRedirect: '/login', failureMessage: false, session: false, failureFlash: true }),
function(req, res) {
res.redirect('/');
});
Here is where I store the users:
passport.use(new GoogleStrategy({
clientID: no,
clientSecret: definitely not,
callbackURL: 'https://no cuz privacy/auth/google'
},
async function(issuer, profile, cb) {
var user = await User.find({ google: true, googleid: profile.id })
if (!user[0]) {
// The Google account has not logged in to this app before. Create a
// new user record and link it to the Google account.
const newUser = await new User({ username: generateUsername(), google: true, googleid: profile.id, googleProfile: profile })
await newUser.save()
return cb(null, newUser);
} else {
// The Google account has previously logged in to the app. Get the
// user record linked to the Google account and log the user in.
console.log('exists')
return cb(null, newUser);
}
}
));
I think you have to do something with the callback function (cb()) to somehow go to app.get('/auth/google') for the redirect, but, all it does is print either exists or new in the console, spinning forever on the client side. Not sure how to redirect after the code determines either account exists or new account.
Edit: I just want to point out that the cb() function could also be done() too. For example:
function(accessToken, refreshToken, profile, done){
console.log("strategy");
console.log(profile);
console.log(accessToken);
console.log(refreshToken);
done(null, profile);
}
^^ Not my code --> PassportJS in Nodejs never call the callback function ^^
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
Unable to retrieve the user email on LinkedIn. I have used passport-LinkedIn and OAuth 2.0. I can interpolate the username and picture. This is the code that I have tried.
var LinkedIn = require('passport-linkedin-oauth2').Strategy;
module.exports = (passport, User) => {
passport.use( new LinkedIn({
clientID: '86ew637ipvirsa',
clientSecret: 'HoEMfqCBGL9SxsIt',
callbackURL: 'http://localhost:3000/auth/linkedin/callback'
}, (accesstoken, refreshToken, profile, done) => {
User.findOne({'linkedin.id': profile.id}, (err, x) => {
if (x) return done(null, x);
var user = {
displayName: profile.displayName,
image: profile._json.pictureUrl,
email: profile.emailAddress,
linkedin: {
id: profile.id
}
};
User.create(user);
User.create(user, (err, x) => done(null, x));
});
}));
};
the npm package being used by you is not properly documented. The author has not explicitly said how you can access the email field from the profile variable.
You can pass in the scope with strategy and get the email fields by logging the profile variable.
passport.use(new LinkedInStrategy({
clientID: LINKEDIN_KEY,
clientSecret: LINKEDIN_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/linkedin/callback",
scope: ['r_emailaddress', 'r_basicprofile'], //pass the scope
state: true
}, function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
console.log(profile); //logging
return done(null, profile);
});
}));
You can also use another package . Here you can explicitly define the profile fields you want to access.
How do I get the message and display it in my router.post('/auth')?
passport.use(new FacebookTokenStrategy({
clientID: 'HIDDEN',
clientSecret: 'HIDDEN'
}, function(accessToken, refreshToken, profile, done) {
console.log(profile);
var user = {id: profile.id, first_name: profile.name[1], last_name: profile.name[0], email: profile.emails[0], profile_picture: profile.photos[0]};
var error = null;
return done(error, user, {message: "HOW TO RETRIEVE THIS MESSAGE!"});
}
));
I've tried to retrieve this message by saying console.log(req.message) or console.log(req.session.message), I just don't know how to get it. I've also tried console.log(req.session.passport.message)
router.post('/auth', passport.authenticate('facebook-token'), function(req, res){
console.log("Verifying");
console.log("HOW TO LOG THAT MESSAGE HERE?");
if(req.isAuthenticated()){
console.log(req.session.passport.user);
}else{
console.log("NOT");
}
});
I don't think that the third argument is passed in any way if the authentication was successful (which in your case it always is; by default, Passport will return a 401 when authentication was unsuccessful, and your handler wouldn't get called at all).
However, you can add extra properties to req if you configure the strategy to pass it to the verification callback:
passport.use(new FacebookTokenStrategy({
clientID: 'HIDDEN',
clientSecret: 'HIDDEN',
passReqToCallback : true,
}, function(req, accessToken, refreshToken, profile, done) {
req.message = 'Your Message Here';
...
}
}))
And then in your handler, you can access it as req.message as well.