I had a small web app that was using the Twitter API 1.0 user_timeline function to quickly get a user's recent tweets without authentication. However, now every call requires oAuth which I'm terrible at. I know there's an application only authentication method, which is what I want since this is an automated app and not a user based one.
The application was built in node.js so a suggestion for a module that supports app-based oAuth would be great. The main thing is I don't have nor need a callback page, which most assume, since all I'm trying to do is get the last few tweets from a handful of specific Twitter accounts which the app tracks. Likewise any links to good oAuth educational resources or, better yet, Twitter 1.1 HTTP request walkthroughs would be much appreciated.
Thank you for your time.
Twitter API 1.1 allows only authenticated requests. But the good news is that the oAuth based authentication is not that difficult. To use it:
Generate the four oAuth keys you need. Go to https://dev.twitter.com/apps/new and register your app.
Install package ntwitter on your machine.
Configure the four keys in your app. See the package page on how to do it.
Construct request and get results. See this page on how to make requests.
I find oAuth to be easier and prefer this way.
The package EveryAuth does authentication pretty well, too. Also, ntwitter isn't being updated very regularly right now; I found mtwitter to be much better. I suck at explaining stuff, so I'll just show you how I did it:
var mtwitter = require('mtwitter');
var twit = new mtwitter({
consumer_key: { your app consumer key },
consumer_secret: { your app consumer secret },
access_token_key: { get this from oauth or everyauth or whatever },
access_token_secret: { get this from oauth or everyauth or whatever }
});
twit.get('/statuses/user_timeline', { include_entities: true },
function (err, data) {
if (err) {
console.log(err.toString());
}
else console.log(JSON.stringify(data));
});
Related
const ClientOAuth2 = require('client-oauth2');
const oauth2 = new ClientOAuth2({
clientId: 'clientId',
clientSecret: 'clientSecret',
accessTokenUri: 'https://fakeurl.com/v1/auth/token',
});
oauth2 .credentials.getToken().then(function (user) {
console.log(user);
}).catch(function (error) {
console.log(error);
});
Is there a way i can include proxy settings when requesting for a token given i am running this code inside a corporate network
I had a quick look and couldn't find an easy way to do it. Other than proxy features I noticed also that it is missing Open Id Connect features such as these:
Looking up metadata
Authorization Code Flow (PKCE)
Calls to the User Info Endpoint
REQUIREMENTS
Choosing a library for your apps is an important decision, and here are a few common things people usually look for:
Standards Based (works for any Authorization Server)
Certified as following the latest OAuth 2.1 and Open Id Connect recommendations
Supports HTTP proxying (highly useful to view OAuth messages when developing)
NODEJS SOLUTION
If you are using Node it might be worth considering the node openid-client library, which is the one I use. Here is some relevant code from an API of mine:
Looking up metadata - note that an agent can be supplied to support proxying
Setting the HTTP proxy - I use TunnelAgent.httpsOverHttp to proxy calls to HTTPS OAuth URLs
OAuth Operations - note that there are some custom classes that make these tasks easier
I have a node.js server which authenticates using google-passport-oauth2. My server-side code looks like that from the documentation:
app.get('/auth/google',
passport.authenticate('google', { scope:
[ 'https://www.googleapis.com/auth/plus.login',
, 'https://www.googleapis.com/auth/plus.profile.emails.read' ] }
));
app.get( '/auth/google/callback',
passport.authenticate( 'google', {
successRedirect: '/auth/google/success',
failureRedirect: '/auth/google/failure'
}));
I figure that /auth/google redirects to google's login, and when permissions are recieved, the google profile and token are sent to the callback /auth/google/callback.
Now I am making an android app which wants to authenticate with this API. I'm using the directions for integrating Google Sign-In to do the authentication on google's end. Now my android app has the profile and token and wants to verify it with my server.
I've tried doing this with passport-google-token and passport-google-id-token (not sure the difference...), but it didn't work for whatever reason. Now I'm looking at other possibilities, like a Google Client API library for node.js, but it seems bulky. Then there's the tokeninfo endpoint, which involves an extra request and more latency. Or maybe I should look at express-jwt?
And suddenly, I wonder... couldn't I just pass the token from my android app to the server at auth/google/callback? That would make things a little simpler. I think this must be a pipe dream, because I haven't found any information about doing it. But if it's possible, how should I format the token/profile data in the request so the passport.authenticate() method recognizes it? (JSON, form data, headers)
If this can't be done, I'm taking suggestions for well-documented token verification libraries for node...
I still don't know about reusing the google-passport-oauth2 route, but I did figure out how to validate Google's idToken using passport-google-id-token.
The documentation says:
The post request to this route should include a JSON object with the
key id_token set to the one the client received from Google (e.g.
after successful Google+ sign-in).
But it only works if it's sent as a query string (GET or POST works).
https://localhost:8888/auth/googletoken?id_token=xxxxxxxxxx
I have a feeling this is not the most secure method, but I'll have to deal with that later.
EDIT: It turns out, the token is useless without the client ID (in your app), so it's OK to send it by querystring.
EDIT 2: One of the google-id-token devs has reminded me that the JSON will only be received if body-parser has been installed.
I'm working in a web app which handle resources from a Mongo database, for such resources I'd like to offer an API, so a future mobile application can seize it or consume it from a raw client.
However I'd like to have web app consuming same API, here is where I get a bit confused about how to properly implement this.
Here is what I've done so far:
API Auth:
app.route('/api/auth/')
.post(function (request,response) {
var email = request.body.email;
var password = request.body.password;
var login = new Account({"local.email":email,"local.password":password});
Account.findOne({"local.email":email}, function (err,user) {
if (err) {
response.send(500);
}
if (!user) {
response.send(404);
}
else {
user.validPassword(password, function (err,matched) {
if (err) {
response.send(500);
}
if (matched) {
var uuidToken = uuid.v4();
redisClient.set(uuidToken,user._id,redis.print);
redisClient.expire(user._id,100);
response.send(uuid);
}
else {
response.send(403);
}
});
}
});
});
So basically I receive consumers username and password, I authenticate it against database, If it matches I reply a token, (actually an UUID). That token gets stored at Redis paired with the user id in databse. Every future request to any API route will verify for such token existance.
Here I wonder:
How should I manage the token TTL, and renewal upon future requests?
How can I control requests per time windows limits?
Is there any security caveat in the approach I'm taking?
Website Auth:
Basically I perform SAME username-password authentication against database and I then:
1. Start a new server session.
2. Naturally, offer back a cookie with session ID.
3. I create then the Redis UUID and user ID record, which API will check. I guess this is OK as there's any sense in requesting POST /api/auth authenticating again.
Here I wonder:
Is this a best approach?
Should I include any token salt to distinguish a pure API consuming request from a request from web app?
Is there any security caveat in the approach I'm taking?
Should I include more tokens?
This is example of POST /login:
app.route('/login')
.post(function (request,response,next) {
var email = request.body.email;
var password = request.body.password;
var login = new Account({"local.email":email,"local.password":password});
Account.findOne({"local.email":email}, function (err,user) {
if (err) {
response.redirect('/error');
}
if (!user) {
var cookie = request.cookies.userAttempts;
if (cookie === undefined) {
response.cookie('userAttempts',1);
}
else {
response.cookie('userAttempts',(++cookie));
}
response.redirect('/');
}
else {
user.validPassword(password, function (err,matched) {
if (err) {
// Redirect error site or show err message.
response.redirect('/error');
}
if (matched) {
var session = request.session;
session.userid = user._id;
var uuidToken = uuid.v4();
redisClient.set(uuidToken,user._id,redis.print);
redisClient.expire(uuidToken,900);
response.cookie('email',email);
response.redirect('/start');
}
else {
var cookie = request.cookies.passwordAttemps;
if (cookie === undefined)
response.cookie('passwordAttemps',1);
else {
var attemps = ++request.cookies.attemps
response.cookie('passwordAttemps', attemps)
}
response.redirect('/');
}
});
}
});
})
I think I could get rid of using and writing a typical session implementation and depend somehow on the similar token based auth the API has.
What you have there is on the right track and basically replaces some of the functionality of cookies. There are a few things to consider though, and you've touched on some of them already.
While using a UUID (v4 I'm guessing?) is good in that it's nondeterministic and "random", on its own the token is worthless. Should redis lose data the token no longer has any context. Nor can you enforce expirations without help from redis. Compare this to a JWT which can carry context on its own, can be decrypted by anybody with the correct key, can handle expirations, and can enforce further common application level constraints (issuer, audience, etc).
Rate limiting. There are a number of ways to handle this and few of them are tied directly to your choice of token scheme aside from the fact that you'd probably use the token as the key to identify a user across requests in the rate limiter.
Transparently passing the token in both a web app and on other clients (mobile app, desktop app, etc) can be a huge pain. In order to access private resources the user will need to pass the token in the request somewhere, likely the headers, and in the case of a web app this means manual intervention on your part to include the token in each request. This means hand coded ajax requests for all authenticated requests. While this can be annoying, at least it's possible to do, and if you're writing a single page app it's likely you'd do that anyways. The same can be said for any mobile or desktop client. Since you already have to make the HTTP request directly in code anyways, why does it matter? Now imagine the scenario where an HTTP GET endpoint, which returns an html page, can only be accessed with proper authentication. In the case of a web app the user is very likely going to access this via a browser redirect or by typing it directly into the URL bar. How is the token added to the request? Other than using cookies, which you're explicitly not using because mobile and desktop clients do not implement them, this is not really possible. However, if your API clients can always modify the HTTP request structure this isn't really a problem.
Now for a shameless plug, our team has a library we use for this. It's mostly used internally and as such is pretty opinionated on its dependencies (express, redis), but hopefully it can help you here. In fact, that library is pretty much just a JWT wrapper around what you have in place. If you decide to use it and notice any issues or deficiencies feel free to file any issues on github. Otherwise there are a whole bunch of other JWT based session management modules on npm that look promising. I would check those out regardless as there are very likely better modules out there than ours. Again, ours is used internally and came about from a pretty specific set of use cases so the chances that it captures all of yours are pretty slim. On the other hand, it sounds like you're using a similar stack so maybe the shoe fits.
If you do use ours it may seem odd that there's a split in the API surface on that module in that you can choose to store data directly in the JWT claims or in redis. This was deliberate and I think your examples illustrate a good use case for both sides. Typically what we do is store the user's email and name in the JWT claims, then store more dynamic session data in redis on their session. For example, upon logging in you'd add the issuer, audience, and user's email to the JWT claims but leave off anything related to "userAttempts". Then upon failed attempts you would add or modify the "userAttempts" on the session data stored in redis related to that JWT. Once a JWT is set it's not possible to modify its contents without generating a new one, so be aware that if you decide to keep relatively dynamic data in the JWT you'll have a constant exchange of old and new JWT's between the server and client.
I am using passport, and would like to use the Google Contacts API version 3.0 to sync Google contacts with my application (which would suddenly become 10 times more useful).
Has anybody done this? If so, do you have some example code? Is it even possible to use passport authentication to get it all working?
This comes in two parts, authorization, and then the actual request.
It is basically using OAuth2 protocol, where you redirect the client to google url with scopes(You must at least have https://www.google.com/m8/feeds in your scopes to be able to read and write contacts) and your client id/secret(get them by registering your app. Then google will redirect the user back with the access token on the URL.
You don't need to do this yourself, because there are different modules that already does this:
passport-google-oauth
This makes it easy and assuming you are already using passport, this probably what you want. It is written by the author of passportjs. Just follow the example in it for OAuth 2.0 strategy. Note that you need to you add the right scopes when you are calling passport.authenticate('google', ...). This module when it gets the token, it will get the user profile, so you have to have one of the 3 scopes below:
passport.authenticate('google', { scope: [ // One of the next three `auth` scopes are needed.
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/plus.login',
'https://www.google.com/m8/feeds'
] }),
googleapis
This is module is officially supported by google and created by google employees. You can use it to authenticate, but sadly it doesn't support gData, which contains google contacts. You can check the example to see how you can get the token. You only need the m8/feeds scope with this module, no need for the other ones if you don't want to get the user profile.
gdata-js
This is a non-popular non-maintaining module, but it is more lightweight than the previous two modules. It might need a little polishing out of the box. I suggest also reading the source for understanding the api right.
Once you got the tokens, then you go for the slightly easier part, making the requests and getting the data.
If you read the docs, it's actually very easy. For example to get all contacts(almost all, it's paginated), you need to make a GET request to this url:
https://www.google.com/m8/feeds/contacts/default/full?alt=json&oauth_token=THE_ACCESS_TOKEN
Again there are many modules that can help you in this.
google-contacts
node-gdata
gdata-js Read the source to understand it's api. It's pretty easy actually:
var client = require('gdata-js')(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET);
client.setToken({ access_token: accessToken, refresh_token: refreshToken });
client.getFeed('https://www.google.com/m8/feeds/contacts/default/full', function (err, result) { ... });
Google's official API for NodeJS doesn't support Contacts API, only the People API.
You can connect with Contacts API using the official googleapis library if you're already using it for other purposes by sending a request to the Contacts API after creating the auth client.
Given that you already have the access token of the user (e.g. if you generated it using Passport, here's the code:
const {google} = require("googleapis");
const authObj = new google.auth.OAuth2({
access_type: 'offline',
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
});
Refresh access token automatically before it expires
authObj.on('tokens', (tokens) => {
const access_token = tokens.access_token
if (tokens.refresh_token){
this.myTokens.refreshToken = tokens.refresh_token
// save refresh token in the database if it exists
}
this.myTokens.accessToken = tokens.access_token
// save new access token (tokens.access_token)
}
authObj.setCredentials({
access_token:this.myTokens.accessToken,
refresh_token:this.myTokens.refreshToken,
});
Make the request to Contacts API (Google uses Gaxios for making the requests to their APIs although it's not documented officially in googleapis, so just be aware that they might change remove/change the request call in the future without documenting it)
authObj.request({
headers:{
"GData-Version":3.0
},
params:{
"alt":"json",
//"q":"OPTIONAL SEARCH QUERY",
//"startindex":0
"orderby":"lastmodified",
"sortorder":"descending",
},
url: "https://www.google.com/m8/feeds/contacts/default/full"
}).then( response => {
console.log(response); // extracted contacts
});
I was looking for a way to let my client authorize with the facebook JS SDK and then somehow transfer this authorization to my node server (so it can verify requests with the fb graph api)
I stumbled across:
https://github.com/jaredhanson/passport-facebook/issues/26
&
https://github.com/drudge/passport-facebook-token
what seems to be an entirely different strategy from passport-facebook.
Am I correct when assuming that:
One logs in with the fb JS SDK, and then the facebook-token strategy somehow extracts the token and fb id from the document or body object?
Or is there any other decent way to achieve this? I'm namely trying to avoid the redirects enforced by the server SDKs
I've spent a couple of days this week trying to figure out the best way to use Facebook Authentication for a private API, using passport.js — passport-facebook-token is perfect for this.
You are correct in assuming these are two separate authentication strategies. You don't need passport-facebook installed to use passport-facebook-token.
If you have Facebook authentication implemented in the client-side JS (or iOS etc.), and are looking for a way to then authenticate API requests using your user's Facebook authToken, passport-facebook-token is a really elegant solution.
passport-facebook-token works totally independently of passport-facebook, and basically handles the redirects required by Facebook internally, before passing the request along to your controller.
So to authenticate an API route using passport-facebook-token, you'll need to set up a passport strategy like so:
passport.use('facebook-token', new FacebookTokenStrategy({
clientID : "123-your-app-id",
clientSecret : "ssshhhhhhhhh"
},
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`
}
));
It's worth noting that the User.findOrCreate method used in the passport-facebook-token Readme is not a default mongo/mongoose method, but a plugin that you'll have to install if you want it.
To use this auth strategy as middleware for any of your routes you'll need to pass it an access_token object either as a URL parameter, or as a property of the request body.
app.get('/my/api/:access_token/endpoint',
passport.authenticate(['facebook-token','other-strategies']),
function (req, res) {
if (req.user){
//you're authenticated! return sensitive secret information here.
res.send(200, {'secrets':['array','of','top','secret','information']});
} else {
// not authenticated. go away.
res.send(401)
}
}
NB. the access_token property is case-sensitive and uses an underscore.
The documentation for passport-facebook-token isn't extensive, but the source is really well commented and pretty easy to read, so I'd encourage you to take a look under the hood there. It certainly helped me wrap my head around some of the more general ways that passport works.