how to use access token to authenticate user after login through twitter in node.js passport - node.js

I need to build a token based authentication on my node.js app , that the user can use the his facebook or twitter credential to login my app, and use access token to get to resource. this post is suggesting to once authenticated through facebook or twitter or other, use access token on every request, and Session is NOT needed at all
For example
GET /api/v1/somefunction?token='abcedf'
The client gets the access token from the response.
The client calls some server api with the token argument.
so the following code, is to authorize user through twitter, if my app doesn't find my user information, then store user information into the database.
passport.use(new TwitterStrategy({
consumerKey: config.twitter.clientID,
consumerSecret: config.twitter.clientSecret,
callbackURL: config.twitter.callbackURL
},
function(token, tokenSecret, profile, done) {
console.log('TwitterStrategy /auth/twitter.............',profile.id, profile.displayName, profile.username, profile.emails[0], profile._json.avatar_url);
userModel.findUserByQuery({ 'social.twitter.id': profile.id }, function (err, user) {
if (!user) {
console.log('twitter user not found'.red);
userModel.createNewUser( { username:profile.username,
email:profile.emails[0].value,
img:profile._json.avatar_url,
fullname:profile.displayName,
password:profile._json.avatar_url,
social:{twitter:{id:profile.id,avatar:profile._json.avatar_url, name:profile.username,token:accessToken} }},
function(err,data){
if(err) return done(err);
else if(!data) return done(null, false, { message: 'can not create your profile in database' });
else {
console.log('save the new twitter user into database'.green, data._id);
return done(err, user);
}
})
} else {
console.log('twitter user found'.green);
return done(err, user);
}
})
}
))
However, I have two questions,
1. how to send the access token to the client for the following requests
in the code, after authenticated from twitter, I get the access token and send this token to the client on the browser, since the token is embedded in the url parameter, I tried the code
res.redirect ('/users/profile ? token = blabla '), but in the client browser, the url is still shown as '/users/profile' rather than '/users/profile ? token=blabla'
2. once authenticated from twitter, the following request with token is going through my app locally( which I store the token in database, and compare the following token to verify) or still to twitter API to authenticate?
if in the first situation, so I should store the token into the database, in order to compare the following request in token in the following requests to my app? is that right

I'm also trying hard to get this, and just found this rather relevant answer: Call Bitbucket REST API using 2leg oauth token
I just can't get how to do this with passport? Particularly, how to get ouath instance from passport authenticated session, to do oauth.get(...), as described here: https://github.com/ciaranj/node-oauth
UPDATE: Jared (author of passportjs) has explained this is wrong approach in the google groups thread below, and recommends to use https://github.com/mikeal/request.
This is how it works for me:
var oauth = {
consumer_key: process.env.BB_CONSUMER_KEY,
consumer_secret: process.env.BB_CONSUMER_SECRET
};
passport.use(new BitbucketStrategy({
...
function(token, tokenSecret, profile, done) {
oauth = extend(oauth, {
token: token,
token_secret: tokenSecret
});
}
Note, tokens above may need be persisted per user in clustered environment.
Later, to access api, do:
request.get({url: 'protected end point', oauth: oauth})
Hope it will help someone!

Related

How to use PassportJS with JWT in a REST API

I'm currently working on building a REST API where users can authenticate themselves via different passport strategies (google, facebook). The authentication has to be done without a session.
Now I've already worked on the local strategy and that works like so;
application POST /login to API and then when the user entered the right credentials they will get some payload back like so
[
{
"tokenType": "refresh",
"expiresIn": 604800000,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImlhdCI6MTY0MDc4NzA4MCwiZXhwIjoxNjQxMzkxODgwfQ.zdxdpX8NkiSTsbZj0xOd18RdbLjeSsQpkikLGW71xrE"
},
{
"tokenType": "access",
"expiresIn": 7200000,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImlhdCI6MTY0MDc4NzA4MCwiZXhwIjoxNjQwNzk0MjgwfQ.EBDuJqQYT-D0bnYbC76_khe6b29c80R4pMyEaBNKLKE"
}
]
However, the problem with the google and facebook strategy is that they work via OAuth. I'm struggling to find a way to send the above information (like with my local strategy) to the client after the OAuth authentication has succeeded.
These OAuth services work with a return URL like /auth/facebook/return. But this return URL is on the API which then can't send the information over to the client (or can it?).
How can I do this?
You can use passport-facebook-token that is altogether a different strategy from passport-facebook. It does provide the token that can be used to authenticate users.
passport.use('facebook-token', new FacebookTokenStrategy({
clientID : "your-client-id",
clientSecret : "secret"
},
function(accessToken, refreshToken, profile, done) {
// console.log(profile);
var user = {
'email': profile.emails[0].value,
'name' : profile.name.givenName + ' ' + profile.name.familyName,
'id' : profile.id,
'token': accessToken
}
// You can perform any necessary actions with your user at this point,
// e.g. internal verification against a users table,
// creating new user entries, etc.
return done(null, user); // the user object we just made gets passed to the route's controller as `req.user`
}
));
Use passport.authenticate(), specifying the 'facebook-token' strategy, to authenticate requests. You need to use it as middleware for any route to authenticate.
app.post('/auth/facebook/token',
passport.authenticate('facebook-token'),
function (req, res) {
// do something with req.user
res.send(req.user? 200 : 401);
}
);
I would suggest you check this link and the code under the hood that is well documented.

Attach the current user to the request with bearer strategy in passport azure ad

I have a NodeJS API server using express and passport for authentication. I am using the passport azure ad bearer strategy for authentication with Microsoft Azure AD. In the examples provided in the documentation(https://github.com/Azure-Samples/active-directory-node-webapi/blob/master/node-server/app.js#L50), the owner (currentUser) is a javascript variable defined globally. How do I attach the user to the request so that I can do something like
server.post('/user', passport.authenticate('oauth-bearer', {
session: false
}), function(req, res, next){
console.log(`I am the current user ${req.user}`);
});
From the example mentioned in the OIDC strategy, I have seen a deserializeUser and serializeUser function that would allow the user ID to be stored in the session, However, in the bearer strategy, we do not have any sessions maintained as authentication will be performed for every incoming request.
This may be a gap in my understanding. I have gone through the documentation for the individual libraries. Please help me if there is a way this can be done
Following is the sample code via which you can embedd the yser object to request object . Thus when you will do ${req.user} in post callback you will get the user object
const BearerStrategy = require('passport-azure-ad').BearerStrategy;
var bearerStrategy = new BearerStrategy(options,
function(token, done) {
findById(token.oid, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
// "Auto-registration"
return done(null, token);
}
const owner = token.oid;
return done(null, user, token);
});
}
);

Post To Twitter on Behalf of Another User using Node.js, express, twit, and passport-twitter

Using the Twitter API, I'm trying to post a tweet on behalf of a Twitter user.
I'm using node and the passport-twitter and twit modules.
Some resources:
I followed this video tutorial NodeJS and ExpressJS: Using Twitter
authentication via Passport.
Sourcecode for the tutorial
here.
Passport-twitter documentation
twit documentation
I successfully authenticated with passport-twitter following the tutorial above.
I also successfully posted using twit on my twitter developer account.
However, I'm having trouble combining these two things; trying to post to twitter on behalf of another user. For that, I need to get the user's access token and access token secret. Then, I need to make a post request to the Twitter API with that information.
I'm not sure where to put the post request in the passport-twitter code. I tried putting it in the second route which is the URL to which Twitter redirects the user after they have signed in.
app.get('/twitter/login', passport.authenticate('twitter'))
app.get('/twitter/return', passport.authenticate('twitter', {
failureRedirect: '/'
}), function(req, res) {
//Post using twit
//grab access token and access token secret from the request query
const access_token = req.query.oauth_token;
const access_token_secret = req.query.oauth_verifier;
//set the configurations with the access token and access token secret that we just got
const config = {
consumer_key: <consumer key here>,
consumer_secret: <consumer secret here>,
access_token,
access_token_secret,
timeout_ms: 60*1000,
strictSSL: true
}
//pass in the configurations
var T = new Twit(config);
//post
T.post('statuses/update', { status: 'hello world!' }, function(err, data, response) {
if (err)console.log("oops, didn't tweet: ", err.message);
})
res.redirect('/');
})
But I got an error: Invalid or expired token.
I expected it to work because the authentication worked.
This is my first time using OAuth so perhaps I misunderstand how this all works.
Where am I supposed to put the post request?
UPDATE:
I tried posting to my dev account, using my dev account's access token and secret. It worked. Which lead me to believe there is something wrong with the access token and secret for the user.
I think I know partially what’s going.
I assumed that the property oauth_verifier found in the request query object was the access token secret.
const access_token_secret = req.query.oauth_verifier;
But now I don’t think oauth_verifier is the same as the access token secret. oauth_verifier has less characters than my dev account’s access token secret. So it seems that the datatypes are different.
But now I’m trying to figure out where the access token secret is? There are only two properties in the request query object (req.query);
oauth_token
oauth_verifier
Where’s the access token secret for the user?
I solved my issue. It was in the documentation for passport-twitter all along. Man, I spent days on this issue.
The strategy also requires a verify callback, which receives the access token and corresponding secret as arguments, as well as profile which contains the authenticated user's Twitter profile.
-from passport-twitter readMe
In the example in the docs, you can see token and tokenSecret in the params.
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, cb) {
User.findOrCreate({ twitterId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
I read this and saw this before. But assumed this was the the consumer key and consumer secret. I didn't realize it was what I was looking for: the access token and access secret.
So your post to twit would go something like this:
passport.use(new Strategy({
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
callbackURL: 'http://localhost:3000/twitter/return'
}, function(token, tokenSecret, profile, callback) {
const configs = createConfigs(token, tokenSecret);
// Post to twitter
var Twit = require('twit')
var T = new Twit({
consumer_key: '...', //get this from developer.twitter.com where your app info is
consumer_secret: '...', //get this from developer.twitter.com where your app info is
access_token: token,
access_token_secret: tokenSecret,
timeout_ms: 60*1000, // optional HTTP request timeout to apply to all requests.
strictSSL: true, // optional - requires SSL certificates to be valid.
})
//
// tweet 'hello world!'
//
T.post('statuses/update', { status: 'hello world!' }, function(err,
data, response) {
console.log(data)
})
return callback(null, profile);
}));

Handling authentication in Nodejs with passport-facebook-token, request coming from frontend Facebook SDK

I am working on a Unity App. For login, there are two methods, one using Email and another using Facebook. In case of login separately, I do not have any problem. Registration and Login with Email works perfectly. And Login with Facebook works perfectly as well. Here's the workflow, I created just to make you clear.
tl;dr [read update]
There's another schema for account, which is used for login.
var Account = new Schema({
email: String,
password: String,
facebookId: String
});
Things to know about the backend API.
Passport is used for Authentication
Successful login returns email and token to the client through API.
On client, token is most to play game and use the overall features.
As I said, I have already covered the part when if a client registers and login using email, then client can use the app. But my confusion is handling the logins with Facebook. Facebook SDK is already integrated with the Unity App, and Login is success.
Now, how can I use the Facebook login information that is generated by the Facebook SDK onto my back end, so that I can authorize the user throughout the system, as done in email login.
Going through other questions in SO and Google, I came across passport-facebook-token, I also tried using the plugin but could not came up with the logic and flow for handling the data from SDK into the Nodejs API. Can someone me help understand how it is done?
Update 1: Using passport-facebook-token
Strategy on index.js
passport.use(new FacebookTokenStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET
}, function(accessToken, refreshToken, profile, done) {
Account.findOrCreate({facebookId: profile.id}, function (error, user) {
return done(error, user);
});
}
));
Controller API
api.post('/auth/facebook/token',
passport.authenticate('facebook-token'),
function (req, res) {
console.log(req.user);
// do something with req.user
res.sendStatus(req.user? 200 : 401);
}
);
Now, there is no error shown, but the data is not inserted into Account Schema, I have this findOrCreate() function in Model.
Account.statics.findOrCreate = function findOrCreate(profile, cb){
var userObj = new this();
this.findOne({facebookId : profile.id},function(err,result){
if(!result){
userObj.facebookId = profile.id;
//....
userObj.save(cb);
}else{
cb(err,result);
}
});
};
you can use facebook-passport for that, you can check the documentation here: https://github.com/jaredhanson/passport-facebook but basically, after you have already set up your developer account and got your keys from the developer site of facebook you can implement a FacebookStrategy object like following where you have to specify your credential and also a callback that in the documentation example is an http request to another resource of an express server where you can then save the data to mongo
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ facebookId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));

Passing Trusted Client Information with oAuth2orize for the "Resource Owner Password Flow"

I am having some issues understanding how to implement the Resource Owners Password Flow with oAuth2rize and passport.js specifically with the transmission of the client_id and the client_secret so that i can do some checks on the client to ensure anything coming into this end point (/token) using the specific "password" grant type is specifically an official application and no others based on the id and secret.
When building out the solution i can get a token back, but that is before i have tried to do any validation on the client. When i try and access the client variable (posted to the end point) passed into the password exchange strategy i receive the user credentials (username, password) which based on documentation is expected but not what i need to achieve here.
I am at a loss to understand how i get the actual client credentials, i can see in the password function source code you can provide additional options to override the default assignment to req['user'] but does that mean i have to provide some sort of code to add to the req object?
I have setup some integration tests and here is how i am calling my endpoint (using SuperTest):
request('http://localhost:43862')
.post('/oauth/token')
.type('form')
.send({ grant_type: 'password' })
.send({ client_id: 'goodClient' })
.send({ client_secret: 'asecret' })
.send({ username: 'good#user.com' })
.send({ password: 'goodpassword' })
.expect(200, done);
For some reason i seem to be completely over thinking this but for some reason am completely stumped....
As expected it was an understanding issue where we were using a local strategy instead of the ClientPasswordStrategy with the user validation happening within the password exchange before issuing a token.
We are now using the ClientPasswordStrategy and within the exchange.password function we are calling and internal call to our user api to validate the user credentials and if ok then issuing the token.
passport.use(new ClientPasswordStrategy(
function(clientId, clientSecret, next){
Client.verify(clientId, clientSecret, function(err, verified){
if(!verified){
return next(null, false);
}
next(null, clientId);
});
}
));
passport.use(new BearerStrategy(
function(token, next) {
Token.getByToken(token, function(err, tokenObj){
if(err)
return next(err);
if(!tokenObj)
return next(null, false);
User.getByUsername(tokenObj.username, function(err, user){
return next(null, user, { scope: 'all' });
});
});
}
));

Resources