Pulling user's name and photo with Passport.js - node.js

I am developing a node.js app and recently figured out how to authenticate via GitHub. I want to know if there is a way to pull a user's profile photo and name so I can display it elsewhere in the app. I found this question, but it looks like Facebook and Google use different methods of obtaining these things.
Can someone point me in the right direction?

Passport module developers usually normalize the user profile object so some standard fields are available in the same way across all modules in this way:
profile.id - assigned by the provider
profile.username - their 'login'
profile.displayName - full name of the user
profile.profileUrl - user's profile page on the provider's site
profile.emails - array of email addresses, but usually just a single address
Thus, you already have the username and/or displayname. One down!
These cover what is consistently needed, but providers can return other information. This naturally depends upon (a) what kind of services the provider offers and (b) the requested scopes.
The provider-specific info isn't lost. It is stored in profile._json next to the normalized properties...and inspecting this will show what else you have to work with.
For Github profile photos/images, you'll be looking for a gravatar_id property to get the user's photo URL.
You can confirm this, using the boilerplate example from passport-github for illustration purposes only, you could do something like this to see what Github is handing back to you so you can evaluate the entire provider response:
passport.use(new GitHubStrategy({
// authentication stuff here, per `passport-github` docs
},
function(accessToken, refreshToken, profile, done) {
// skipping error handling &c for brevity...
fs.writeFile("githubProfile.json", JSON.stringify(profile));
return done(null, profile);
});
}
));
If correct, you could then grab the user photo URL from profile._json.gravatar for use in whatever way you need (saving to database, inserting into a profile page, etc).

Related

How can I allow users to join Google Meet without having to ask?

I'm scheduling a google meet based on specific time and date, and so far it's going well, it generates a google meet link. But the only problem is that I have to ask to join while no one is there to accept. Is there is a way to get around this? knowing that I get the emails of both of the participants.
I'm using a package called google-meet-api
This is the code:
const meetingLink = await Meeting({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
date,
time,
summary: 'Interview',
location: 'Online',
description: 'Interview',
});
if (!meetingLink) {
throw new CustomError('Error creating the meeting, please try again later', 500);
}
console.log(meetingLink) // https://meet.google.com/arr-yrre-t**
If you're the primary user or one of the invitees, then the URL should give you the option to "join the meeting" even if noone else (including the organizer) is present.
Without more details in your question, it's difficult to provide more help.
Are you using this NPM package: google-meet-api?
The NPM package is an implementation of the Google SDK method and is little more than the example code that's provided by Google.
I encourage you to consider writing this code for yourself and saving yourself a mostly redundant depdendency on a 3rd-party NPM package that adds very little value.
The Google documentation page for the calendar Events:insert method (which is what is being used by the google-meet-api package) provides details of the parameters and the request body.
By reviewing the parameters and request body fields, you can confirm to yourself whether you're missing one of the fields that would address your problem.

Twitter OAuth Strategy Access Level & Email Problem

I have a Twitter OAuth strategy like this:
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
userProfileURL: "https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true",
requestTokenURL: 'https://api.twitter.com/oauth/request_token?x_auth_access_type=read',
callbackURL: '/dashboard/auth/callback',
proxy: true
Now, here whenever I include requestTokenURL: 'https://api.twitter.com/oauth/request_token?x_auth_access_type=read', I am not able to access the user's email. If I remove it, I am able to access the email via userProfileURL: "https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true".
I have enabled the request email permission in the developer dashboard. What am I missing? I am using the passport-twitter library for this.
Unfortunately this does not seem possible.
Unfortunately the initial x_auth_access_type setting was created at a point long before the email permission was added, and has only ever allowed one or other of the read or write values to be specified. I think what you’re seeing here is that using that parameter does perform an absolute override on what you have configured on the app settings. I’ll note this as something we should improve in the future, but at the moment I can’t say when or if we’re likely to change that behaviour.
Source: https://twittercommunity.com/t/email-is-not-requested-when-x-auth-access-type-parameter-added/72396/5

How can I protect the loopback explorer by username and password?

I've just started using loopback4 and I would like to protect the /explorer from being public. The user would initially see a page where username and password must be entered. If successful, the user is redirected to /explorer where he can see all API methods (and execute them). If user is not authenticated, accessing the path /explorer would give a response of "Unauthorized". Is there a way to easily implement this?
There is issue talking about a GLOBAL default strategy is enabled for all routes including explorer in https://github.com/strongloop/loopback-next/issues/5758
The way is to specify a global metadata through the options:
this.configure(AuthenticationBindings.COMPONENT).to({
defaultMetadata: {
strategy: 'JWTStrategy'
}
})
this.component(AuthenticationComponent);
registerAuthenticationStrategy(this, JWTAuthenticationStrategy)
But in terms of enabling a single endpoint added by route.get(), it's not supported yet, see code of how explorer is registered. #loopback/authentication retrieves auth strategy name from a controller class or its members, but if the route is not defined in the controller, it can only fall back to the default options, see implementation

How to create a referral link in nodejs

Am trying to figure out a way of creating a unique referral link that directs to my site for each user that signs up for my site, but to be sincere i don't really know how it works out for sure, I have tried googling for it, but i can't find a perfect answer for it, any plugin needed or any way around that.
The user model, no much code i don't have any idea of this
var UserSchema = new mongoose.Schema({
username: String,
password: String,
referralLink: String
})
UserSchema.plugin(passortLocalMongoose);
module.exports = mongoose.model("User", UserSchema )
user sign up
router.post("/register", function(req,res){
var newUser = new User({username: req.body.username,referral: req.body.referral});
User.register(newUser, req.body.password, function(error, user){
if(error){
console.log(error)
req.flash("signerror", error.message)
return res.redirect("/register")
}
//Do the referral link creation stuff here, don't know for sure
})
})
if there is a way for this, would be glad if you help out
How to create a referral link?
Let this be a platform/language agnostic how-to:
Every time new User is created, generate unique link for him to be his unique referral link and store it in DB (For simplicity this could be _id which is unique in MongoDB and is auto-generated - in this case you don't have to create another field). Let's also keep count of how many people registered through this person's link, let it be referredCount.
Referral link could look for example like this: /register?referrer=${_id}, where ${_id} is user unique ID.
Send referral link to user, so he can pass it along to other people, or make it visible in his /account page - obvious step
When someone registers via this link, create new User as usual and after succesful creation, get req.query.referrer from the URL, look into DB for user with this particular ID and increase his referredCount.
Note that it's just a way of doing that, I'm sure there might be many different strategies for it.
I suggest that you create a table/collection for referrals.
Schema could contain:
userId (the user who generated the link)
numberOfUses (the number of times the link can be used)
expires at (incase you want to limit the validity to a specific period)
MongoDB will generate a _id aka referralId
You can modify the registration endpoint to accept an optional param referralId
Whenever someone uses a referal you just get the userId of the person who created the invite link.
To address Your question from the comment:
You can follow #Tomasz suggestion however to keep referral link You can use cookies.
A cookie is a small piece of data which is stored in a user’s web browser when they visit a website. When a customer comes to your website via an affiliate referral link (i.e. yoursite.com/?ref=123), application should store two main browser cookies in order to track the referring affiliate, and the visit. Their names are:
aff_ref - this cookie stores the affiliate's unique ID
aff_ref_visit_id - this cookie stores the visit ID (the visit ID increments by 1, each time any referral link is used until the cookie expires or is deleted).
So You are able to detect if user came to website using referral link by checking the cookie. It is worth to mention that
cookies should remain in the browser throughout the purchase or conversion process to track the correct affiliate so a referral can be generated for that affiliate. The cookies should also remain in the customer's browser for a period of time specified by the site admin or until the customer clears their cookies.
in the user schema .. have a field named referral (either be a name, number or takes another user's Id ) ...on the main site. create a button that will generate a user's personal referral link (using Javascript) so that the link will look like "your-domain.com/register?register=${user._id} ... then on the registration page ... there will be an hidden input field ... which will automatically be field with the query param ...
location.search so that when a user register ... the person that referred them will also be registerd ... then the route will be like
app.post('/register',(req,res) =>{
user.update({id:(req.query.register)},{referral:req.body.name})
...remaining registration routing ...
})

REST API Endpoint for changing email with multi-step procedure and changing password

I need help for creating the REST endpoints. There are couple of activities :
To change the email there are 3 URL requests required:
/changeemail : Here one time password (OTP) is sent to the user's mobile
/users/email : the user sends the one time password from previous step and system sends the email to the new user to click on the email activate link
/activateemail : user clicks on the link in the new email inbox and server updates the new email
To change password :
/users/password (PATCH) : user submits old password and new password and system accordingly updates the new password
Similarly, there are other endpoints to change profile (field include bday, firstname and last name)
after reading online I believe my system as only users as the resource --> so to update the attributes I was thinking of using a single PATCH for change email and change password and along with that something like operation field so the above two features will look like :
For changing email :
operation : 'sendOTPForEmailChange'
operation : 'sendEmailActivationLink'
operation : 'activateEmail'
For changing password :
operation : 'changePassword'
and I will have only one endpoint for all the above operations that is (in nodejs) :
app.patch('/users', function (req, res) {
// depending upon the operation I delegate it to the respective method
if (req.body.operation === 'sendOTPForEmailChange') {
callMethodA();
} else if (req.body.operation === 'sendEmailActivationLink') {
callMethodB();
} else if (req.body.operation === 'activateEmail') {
callMethodC();
} else if (req.body.operation === 'changePassword') {
callMethodC();
} else sendReplyError();
});
Does this sound a good idea ? If not, someone can help me form the endpoints for changeemail and changepassword.
Answer :
I finally settled for using PATCH with operation field in the HTTP Request Body to indicate what operation has to be performed.
Since I was only modifying a single field of the resource I used the PATCH method.
Also, I wanted to avoid using Verbs in the URI so using 'operation' field looked better.
Some references I used in making this decision :
Wilts answer link here
Mark Nottingham' blog link article
and finally JSON MERGE PATCH link RFC
You should make the links that define the particular resource, avoid using PATCH and adding all the logic in one link keep things simple and use separation of concern in the API
like this
1- /users/otp with HTTP Verb: GET -> to get OTP for any perpose
2- /users/password/otp with HTTP Verb: POST -> to verify OTP for password and sending link via email
3- /users/activate with HTTP Verb: POST to activate the user
4- /users/password with HTTP Verb: PUT to update users password
Hashing Security is a must read, IMHO, should you ever want to implement your own user account system.
Two-factor identification should always be considered, at least as an opt-in feature. How would you integrate it into your login scheme ?
What about identity federation ? Can your user leverage their social accounts to use your app ?
A quick look at Google yielded this and this, as well as this.
Unless you have an excellent reason to do it yourself, I'd spend time integrating a solution that is backed by a strong community for the utility aspects of the project, and focus my time on implementing the business value for your customers.
NB: my text was too long for the comments
Mostly agree with Ghulam's reply, separation of concerns is key. I suggest slightly different endpoints as following:
1. POST /users/otp -> as we are creating a new OTP which should be returned with 200 response.
2. POST /users/email -> to link new email, request to include OTP for verification.
3. PUT /users/email -> to activate the email.
4. PUT /users/password -> to update users password.

Resources