While using passport-github, profile.emails is null despite user:email scope - passport.js

I'm trying to get the private email of github user via passport-github.
So this is my code with scope: "user:email":
import passport from "passport";
import GithubStrategy from "passport-github";
passport.use(
new GithubStrategy(
{
clientID: process.env.GH_CLIENT_ID,
clientSecret: process.env.GH_CLIENT_SECRET,
callbackURL: `http://localhost:4000${routes.ghLoginCallback}`,
scope: "user:email",
},
async (accessToken, refreshToken, profile, cb) => {
console.log(profile.emails);
}
)
);
And now I get undefined from profile.emails.
I do get my profile correctly, but with email:null also.
Are there any possible problems that I'm missing?

yeah as #jasonandmonte mentioned, passport-github2 worked for me! Thanks a lot.
However, some people are saying that only passport-github works for them (checkout the thread that #jasonandmonte mentioned), so anyone who are in same issue in future can try both one. (Structure is almost the same.)

Related

Getting "state not found" during msal loginRedirect method

I am attempting to implement msal 2 in my React application. I'm using the msal-react-samples/default as the template for my work. I am able to see me login page and login using the loginRedirect method. But upon returning to my application I'm getting the following error. I saw that someone asked a very similar question (65375241). But it looks like the user abandoned it. I have included additional information below.
errorCode: "state_not_found"
errorMessage: "State not found: Cached State"
Additional Information
Authenticating into ADB2C
MsalConfig:
{ auth: { clientId: "REDACTED" authority: "REDACTED" knownAuthorities:["Redacted, Same as authority"], redirectUri: "http://localhost:3000/AuthTest", navigateToLoginRequestUrl: false }, cache: { cacheLocation: "sessionStorage", storeAuthStateInCookie: false, }, system: { loggerOptions: { ...(logger options from sample) } }
Authentication worked previously with MSAL1.
I'm aware that as of 1/7/2021 the msal-react package is not meant for production environments. I could attempt to change to just use just the msal-browser package if that would help.
I was able to figure out my own error by looking at the the MSAL git repo issue
#azure/msal-browser redirect not working correctly
I will describe my issue here to assist anyone else that has this same error.
It was caused because I had used the addEventCallback method improperly.
I had it implemented in my code as a simple function call. But it needs needs to be put into a useEffect and also issue the removeEventCallback method after consuming it.
I had
instance.addEventCallback((message) => {
console.log(message)
})
rather than
useEffect(() => {
const callbackId = instance.addEventCallback((message) => {
console.log(message)
})
return () => {
if (callbackId) {
instance.removeEventCallback(callbackId);
}
}
}, [instance])

google-api-nodejs-client throws invalid_request error when exchanging code with tokens

I've got a simple client app using react-google-login with this settings:
<GoogleLogin
clientId={config.CLIENT_ID}
scope={config.SCOPES.join(' ')}
buttonText="Login With Google"
onSuccess={response => onSignIn('google', response)}
onFailure={this.failure.bind(this)}
accessType="offline"
responseType="code"
/>
It retrieves the code successfully and sends it to the backend server which is written with NodeJS.
The server-side code looks like this:
const { google } = require('googleapis');
const config = global.config;
const oauth2Client = new google.auth.OAuth2({
clientId: config.google.CLIENT_ID,
clientSecret: config.google.CLIENT_SECRET,
});
// code omitted for the sake of simplicity
var authCode = req.body.authCode; // the provided code by google
const { tokens } = await oauth2Client.getToken(authCode);
return tokens;
When I run the code, it throws the error:
{ error: 'invalid_request',
error_description: 'Missing parameter: redirect_uri' } },
code: '400' }
and if I add redirectUrl to Developer Console, client app and server-side app, I'll get redirect_uri_mismatch error.
I'm kind of stuck here and couldn't find anything useful on the web.
Any workaround would be appreciated.
Found the solution
Based on one of the replies (surprisingly, not the answer) on this post,
All I needed to do was put postmessage instead of the actual URL in my client react-google-login button and in oauth2Client config on the server.
no need for the redirect_uri on Developer Console at all.
<GoogleLogin
clientId={config.CLIENT_ID}
****redirectUri="postmessage"****
scope={config.SCOPES.join(' ')}
buttonText="Login With Google"
onSuccess={response => onSignIn('google', response)}
onFailure={this.failure.bind(this)}
accessType="offline"
responseType="code"
/>
const oauth2Client = new google.auth.OAuth2({
clientId: config.google.CLIENT_ID,
clientSecret: config.google.CLIENT_SECRET,
****redirectUri: 'postmessage'****
});
Did solve the issue. 5 hours of working, searching and beating my head to the desk. I wonder why there's no clear documentation on Google Developers website. Or maybe there are and I couldn't find them.

Passport.js async vs sync deserialization

I'm implementing a payment feature on my app, and my provider requres AccountId (identification of the user in my system) and Email. I've noticed some strange behaviour I cannot explain with Passport.js. First of all, deserialization looks like in docs:
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Now, I get that this is an async operation, however when I form the data for the request, I do:
var data = {
AccountId: toString(req.user._id),
Email: req.user.auth.local.email
// ...
}
For some reason Email gets set correctly, but AccountId always returns [object Undefined]. Well, I thought that maybe it's due to Passport's async nature of deserialization (since it requires time to User.findById()), but why does Email gets set correctly then?
I've found a way of setting AccountId to req.session.passport.user, but it seems like a hack to me.
Your problem is here:
AccountId: toString(req.user._id),
toString is a method of an object. In the browser, simply calling toString assumes that you mean window.toString() and it returns [object Window]. In Node, since the global window does not exist, you get [object Undefined].
I think the way you meant to call that function would be like so:
AccountId: req.user._id.toString(),

two different login with node-passport

I have the same application for 2 sites, the front-site and the backoffice.Both sites require a different condition to login because the backoffice needs to have the is_admin value in "true".
this is my login method
module.exports.verifyCredentials = function (username, password, done) {
mongoose.model("User").findOne({password:password, username:username, is_admin:true}, function(err, user) {
done(err, user);
});
};
and this is in my app.js
passport.use(new passportLocal.Strategy(securityCtl.verifyCredentials));
app.post("/administracion/login", passport.authenticate('local'), securityCtl.doLogin);
The doLogin methods just makes a redirect.
how can I send the frontsite login and the backoffice login to different methods?
Thanks!
Just use different names in each strategy and refers to they by their names in the passport.authenticate method. Now you can specify different methods (verifyFrontSiteCredentials for front-site and verifyBackOfficeCredentials for backoffice respectively) in each strategy. Something like this:
app.js
// front-site strategy
passport.use('front-site', new passportLocal.Strategy(securityCtl.verifyFrontSiteCredentials));
app.post("/administracion/front-site/login", passport.authenticate('front-site'), securityCtl.doLogin);
// backoffice strategy
passport.use('backoffice', new passportLocal.Strategy(securityCtl.verifyBackOfficeCredentials));
app.post("/administracion/backoffice/login", passport.authenticate('backoffice'), securityCtl.doLogin);

implementing passport authentication in node.js with bitly strategy

I'm trying to authenticate to bitly so I can use the link-shortener and track the users' metrics. My implementation is like this:
passport.use(new BitlyStrategy({
clientID: "my client id here",
clientSecret: "my secret here",
callbackURL: "http://website.com/auth/bitly/callback"
},
function (token, tokenSecret, profile, done) {
// Code to put it in the server here.
}
));
And the routes look like this:
app.get('/auth/bitly',
passport.authenticate('bitly'));
app.get('/auth/bitly/callback',
passport.authenticate('bitly', { failureRedirect: '/', failureFlash: true, failureFlash: 'Invalid bitly Authentication try again.' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/');
});
Now I've done everything I can think of to get this working, but I always come up with this stupid error:
Application has thrown an uncaught exception and is terminated:
TypeError: Parameter 'url' must be a string, not undefined
at Object.urlParse [as parse] (url.js:92:11)
at [object Object]._request (C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\node_modules\oauth\lib\oauth2.js:56:22)
at [object Object].get (C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\node_modules\oauth\lib\oauth2.js:196:8)
at Strategy.userProfile (C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\lib\passport-bitly\strategy.js:76:16)
at loadIt (C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\lib\passport-oauth\strategies\oauth2.js:221:17)
at Strategy._loadUserProfile (C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\lib\passport-oauth\strategies\oauth2.js:236:25)
at C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\lib\passport-oauth\strategies\oauth2.js:127:14
at C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\node_modules\oauth\lib\oauth2.js:178:7
at passBackControl (C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\node_modules\oauth\lib\oauth2.js:107:9)
at IncomingMessage.<anonymous> (C:\DWASFiles\Sites\twitter-mongo\VirtualDirectory0\site\wwwroot\node_modules\passport-bitly\node_modules\passport-oauth\node_modules\oauth\lib\oauth2.js:124:7
Anyone have any idea what that means, and where I should start to get it fixed?
I just fixed the bug in passport-bitly and made a pull request: https://github.com/dreadjr/passport-bitly/pull/1
#Bitly API: passport is a popular way to get access tokens in the node world, so it's good to have this strategy working.
We are not super familiar with the passport library over here but we recently posted some simple OAuth code examples in several languages including node.js here: http://bit.ly/bitlyoauthexamples
If you are using dreadjs's passport-bitly strategy, you will get this error. Replace the strategy.js file with that from simo's fork.
As of this date, Simo's corrections have not yet been merged into dreadjr's passport-bitly repository. I can verify that the corrections do work. Basically the original camel-cased _profileUrl should be _profileURL on line 49 of strategy.js. The correct line is:
this._profileURL = options.profileURL || 'https://api-ssl.bitly.com/v3/user/info';
There are changes made in retrieving the JSON information that are needed as well.

Resources