Oauth for Connect-auth for www.500px.com - node.js

I'm trying to extend connect-auth (https://github.com/ciaranj/connect-auth) to connect to http://www.500px.com oauth, but am having issues and can't find a way to debug other than console.log.
I added a strategy five00px.js ( can't name a variable 500px ) as per below, which is a copy of twitter.js strategy with some string substitution.
I keep getting Invalid OAuth Request
Error retrieving the OAuth Request Token: {"statusCode":401,"data":"Invalid OAuth Request"}
I can't really see the OAUTH request as it's in HTTP.
Any idea ?
// five00px.js
/*!
* Copyright(c) 2010 Ciaran Jessup <ciaranj#gmail.com>
* MIT Licensed
*/
var OAuth= require("oauth").OAuth,
url = require("url"),
http = require('http');
module.exports= function(options, server) {
options= options || {}
var that= {};
var my= {};
// Construct the internal OAuth client
my._oAuth= new OAuth("https://api.500px.com/v1/oauth/request_token",
"https://api.500px.com/v1/oauth/access_token",
options.consumerKey, options.consumerSecret,
"1.0A", options.callback || null, "HMAC-SHA1");
console.log('1');
// Give the strategy a name
that.name = "five00px";
// Build the authentication routes required
that.setupRoutes= function(app) {console.log('2setupRoutes');
app.use('/auth/five00px_callback', function(req, res){console.log('3five00px_callback');
req.authenticate([that.name], function(error, authenticated) {console.log('4authenticate');
res.writeHead(303, { 'Location': req.session.five00px_redirect_url });
res.end('');
});
});
}
// Declare the method that actually does the authentication
that.authenticate= function(request, response, callback) {console.log('5authenticate');
//todo: if multiple connect middlewares were doing this, it would be more efficient to do it in the stack??
var parsedUrl= url.parse(request.originalUrl, true);
this.trace('parsedUrl=' + request.originalUrl);
//todo: makw the call timeout ....
var self= this;
if( request.getAuthDetails()['500px_login_attempt_failed'] === true ) {
// Because we bounce through authentication calls across multiple requests
// we use this to keep track of the fact we *Really* have failed to authenticate
// so that we don't keep re-trying to authenticate forever.
delete request.getAuthDetails()['500px_login_attempt_failed'];
self.fail( callback );
}
else {
if( parsedUrl.query && parsedUrl.query.denied ) {
self.trace( 'User denied OAuth Access' );
request.getAuthDetails()['500px_login_attempt_failed'] = true;
this.fail(callback);
}
else if( parsedUrl.query && parsedUrl.query.oauth_token && request.session.auth["500px_oauth_token_secret"] ) {
self.trace( 'Phase 2/2 : Requesting an OAuth access token.' );
my._oAuth.getOAuthAccessToken(parsedUrl.query.oauth_token, request.session.auth["500px_oauth_token_secret"],
function( error, oauth_token, oauth_token_secret, additionalParameters ) {
if( error ) {
self.trace( 'Error retrieving the OAuth Access Token: ' + error );
request.getAuthDetails()['500px_login_attempt_failed'] = true;
this.fail(callback);
}
else {
self.trace( 'Successfully retrieved the OAuth Access Token' );
request.session.auth["500px_oauth_token_secret"]= oauth_token_secret;
request.session.auth["500px_oauth_token"]= oauth_token;
var user= { user_id: additionalParameters.user_id,
username: additionalParameters.screen_name }
self.executionResult.user= user;
self.success(user, callback)
}
});
}
else {
my._oAuth.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, oauth_authorize_url, additionalParameters ) {
if(error) {
self.trace( 'Error retrieving the OAuth Request Token: ' + JSON.stringify(error) );
callback(null); // Ignore the error upstream, treat as validation failure.
} else {
self.trace( 'Successfully retrieved the OAuth Request Token' );
request.session['500px_redirect_url']= request.originalUrl;
request.session.auth["500px_oauth_token_secret"]= oauth_token_secret;
request.session.auth["500px_oauth_token"]= oauth_token;
self.redirect(response, "https://api.500px.com/oauth/authenticate?oauth_token=" + oauth_token, callback);
}
});
}
}
}
return that;
};

Have to use OAuth 1.0 (instead of 1.0A)
my._oAuth= new OAuth("https://api.500px.com/v1/oauth/request_token",
"https://api.500px.com/v1/oauth/access_token",
options.consumerKey, options.consumerSecret,
"1.0",
options.callback || null, "HMAC-SHA1");

Related

Is it possible to catch Twilio webhook error to log them in NodeJS

I'm working on a project with Twilio and NodeJS.
I set up a twilio.webhook() and as a requirement, I need to catch when there is an error and log that.
For example, if the webhook fails with 403 Forbidden I should be able to catch it and log an error in the console about it.
I cannot find a way online and I read Twilio docs here
Twilio doc
I made a validation utility to be able to validate Twilio in several places but cannot log which would be important
const validate = (req, res, next) => {
log.info('Twilio Access Validation');
const { NODE_ENV } = process.env;
const { authToken } = config.get('twilio');
const shouldValidate = NODE_ENV !== 'development';
const validateTwilio = twilio.webhook({ validate: true }, 'authToken');
router.use(validateTwilio);
};
Twilio developer evangelist here.
You can't hook into the validation failure with the webhook function, but you could write your own middleware function that takes inspiration from the webhook function.
Something like this might work:
const { validateExpressRequest } = require("twilio");
function webhook() {
var opts = {
validate: true,
};
// Process arguments
var tokenString;
for (var i = 0, l = arguments.length; i < l; i++) {
var arg = arguments[i];
if (typeof arg === 'string') {
tokenString = arg;
} else {
opts = _.extend(opts, arg);
}
}
// set auth token from input or environment variable
opts.authToken = tokenString ? tokenString : process.env.TWILIO_AUTH_TOKEN;
// Create middleware function
return function hook(request, response, next) {
// Do validation if requested
if (opts.validate) {
// Check if the 'X-Twilio-Signature' header exists or not
if (!request.header('X-Twilio-Signature')) {
// Log error here
return response.type('text/plain')
.status(400)
.send('No signature header error - X-Twilio-Signature header does not exist, maybe this request is not coming from Twilio.');
}
// Check for a valid auth token
if (!opts.authToken) {
// Log error here
console.error('[Twilio]: Error - Twilio auth token is required for webhook request validation.');
response.type('text/plain')
.status(500)
.send('Webhook Error - we attempted to validate this request without first configuring our auth token.');
} else {
// Check that the request originated from Twilio
var valid = validateExpressRequest(request, opts.authToken, {
url: opts.url,
host: opts.host,
protocol: opts.protocol,
});
if (valid) {
next();
} else {
// Log error here
return response
.type('text/plain')
.status(403)
.send('Twilio Request Validation Failed.');
}
}
} else {
next();
}
};
}

Segregation of multiple routes for pages and Apis with JWT using Express in Node.js

Is there any way by which, I could segregate my multi Api(S) like
employees Api and its page redirection
customer Api and its page redirection etc !
Since currently what, I am doing is
var employees = require('./routes/employees');
var customers = require('./routes/customers');
app.use('/customers', isAuth, customers);
app.use('/employees', isAuth, employees);
My JWT Part look like this
function isAuth(req, res, next) {
var token = req.body.token || req.param('token') || req.headers['x-access-token'];
if (token != undefined) {
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({
success: false,
message: 'Failed to authenticate token.'
});
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
})
}
} else {
//check whether request is api or normal request !
var string = req.url,
substring = "api";
if (string.indexOf(substring) !== -1) {
res.status(403).send({
success: false,
message: 'No token provided.'
})
} else {
//check whether request is authenticated or not !
if (req.isAuthenticated())
return next();
/* res.status(401).json({authenticated: false});*/
res.redirect('/login');
}
}
}
Any recommendations, improvements how to improve on below pointers with reference from above code snippets
separate routes of page redirection and apis much like in
phoenixframework of elixir.
jwt api routes authentications without current overcomplications of
aforementioned code snippets !.
here is code snippets of my elixir running under phoenix framework with simple api and page level segregation without jwt !
defmodule HelloPhoenix.Router do
use HelloPhoenix.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
# Other scopes may use custom stacks.
scope "/api", HelloPhoenix do
pipe_through :api
# resources "/users", UserController, except: [:new, :edit]
resources "/users", UserController do
post "/filterbackend", UserController,:filterbackend
post "/bulkcreate", UserController,:bulkcreate
post "/testpost", UserController,:testpost
post "/filterRecordset", UserController,:filterRecordset
end
end
end

Check Oauth2 token exists and valid in Node.js Rest Client With Bluebird

I am writing a Node.js client for a REST API that uses OAuth2. I am using Bluebird and promises (and sending the access token in the header) and I was wondering when would be a good time to check if the access token is already granted (exists) or still valid (not expired).
So far, I have come up with this:
'use strict';
var Bluebird = require('bluebird');
var request = Bluebird.promisifyAll(require('request'), { multiArgs: true });
var Oauth = require('oauth');
var OAuth2 = OAuth.OAuth2;
var _ = require('lodash');
function Client(options) {
this.options = _.assign({
url: '<API URL>',
oauth2Url: 'oauth2/token',
apiVersion: process.env.apiVersion,
consumerKey: process.env.consumerKey,
consumerSecret: process.env.consumerSecret
}, options);
if (!this.options.url) {
throw new Error('Missing client url.');
}
...
if (!this.options.consumerSecret) {
throw new Error('Missing consumer secret.');
}
if(!this.access_token){
var oauth2 = new OAuth2(
this.options.consumerKey,
this.options.consumerSecret,
this.options.url + this.options.version,
null,
this.options.oauth2Url,
null);
oauth2.getOAuthAccessToken(
'',
{'grant_type':'client_credentials'},
function (e, access_token, refresh_token, results){
this.access_token = access_token;
this.refresh_token = refresh_token;
done();
});
}
}
Client.prototype.queryApi = function (options, callback) {
return request.postAsync({
headers: {
Authorization: 'Bearer ' + access_token
},
url: this.options.url + this.options.apiVersion,
body: JSON.stringify(options)}).
then(function (result) {
var json = JSON.parse(result[1]);
if (_.isFunction(callback)) {
callback(null, json);
}
return json;
}).
catch(function (err) {
if (_.isFunction(callback)) {
callback(err);
return;
}
throw err;
});
};
module.exports = Client;
I am new to both Oauth/Oauth2 and Node.js and I was just wondering if I am checking for the access token in the right place and how/where can I also check if it expired or not. Thanks!
First of all there is two way to check whether access token is expired or not
By knowing token_expiration value from your oauth app.In this case you need to keep task running on your app that will determine wheter access_token is expired or not.(Not recommended way of handling access token)
Handle the response from Authorization server stating that your acces token has been expired.In this case you need to get new access token by presenting refresh token.
You can write 'tokenPersistanceFunction' that will be called when your oauth values(access_token,refresh_token) are updated.
I have modified your code to reflect these changes
function tokenPersistanceFunction(updatedOauth){
// Here you will get Updated Oauth values
// Save these to DB
return saveAccessToken(updatedOauth.access_token, updatedOauth.refresh_token);
}
Client.prototype.queryApi = function (options, tokenPersistanceFunction, callback) {
return request.postAsync({
headers: {
Authorization: 'Bearer ' + access_token
},
url: this.options.url + this.options.apiVersion,
body: JSON.stringify(options)}).
then(function (result) {
// You have some indication from your oauth server, that your access_token is expired.
// You can check your response here to know whether access_token is expired or not.
// If access_token is expired, Make request to refresh access token.
// In your case
if(AccessTokenIsExpired){
// Function that will make request to refresh access_token by presenting refresh_token
return <functionThatRefreshesAccessToken>( refreshAccessTokenOptions,tokenPersistanceFunction)
.then(function(result){
//Extract access_token, refresh_token from response
// call 'tokenPersistanceFunction' to store these token in your DB.
return tokenPersistanceFunction(updatedOauth);
})
.then(function(savedOauthTokensSuccess){
// Now you have the updated Oauth tokens, you can make request to get resource
// this call will return you the actual response.
return queryApi(options, tokenPersistanceFunction, callback);
})
}else{
var json = JSON.parse(result[1]);
if (_.isFunction(callback)) {
callback(null, json);
}
return json;
}
}).
catch(function (err) {
if (_.isFunction(callback)) {
callback(err);
return;
}
throw err;
});
};

How to retrieve user's additional information from Azure Mobile/App Services?

I need to get the user's extra information from social accounts like Facebook and Google+. When I first read about Azure Mobile Services I thought it to be the holy grail of social authentication. Well, after a full week of hair pulling I'm starting to reconsider my first impression. It does authenticate as easily as it could possibly do. I configured Google+ and FB to work with Azure, configured Azure to use the key/secret from each provider and it all just worked. I was able to login perfectly. The problem started when I tried to get information from the logged user, which I honestly think is basic!
Azure Mobile Services returns the UserId and a Token that you can not use to request the extra info on the selected provider. So even if I were to create a second request using FB's graph API for instance, that wouldn't work (I've tried!). That token is Azure's own token. So I found out from several Carlos Figueira (SE at Azure) posts that I should customize my Azure script, make a request to Azure and then I'd be able to get it working.
I've also read several posts from Carlos Figueira on how to implement that extra functionality and even though that was not what I was looking for (customizing the server) I decided to work with that. But my return type is a MobileServiceUser and that type only has 2 properties: UserId and MobileServiceAuthenticationToken. So even after adding the server script from Carlos I couldn't retrieve the extra information from my Xamarin App.
I've read a lot of things, researched a lot and couldn't find an answer =/ By the way this is not the answer:
How to get user name, email, etc. from MobileServiceUser?
Did anyone manage to make it work?
PS: I'm not posting any code here because it's working. If you think checking some part of my code would help decipher the problem just let me know.
Thanks in advance!
EDIT:
Script
function insert(item, user, request) {
item.UserName = "<unknown>"; // default
user.getIdentities({
success: function (identities) {
var url = null;
var oauth = null;
if (identities.google) {
var googleAccessToken = identities.google.accessToken;
url = 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' + googleAccessToken;
} else if (identities.facebook) {
var fbAccessToken = identities.facebook.accessToken;
url = 'https://graph.facebook.com/me?access_token=' + fbAccessToken;
} else if (identities.microsoft) {
var liveAccessToken = identities.microsoft.accessToken;
url = 'https://apis.live.net/v5.0/me/?method=GET&access_token=' + liveAccessToken;
} else if (identities.twitter) {
var userId = user.userId;
var twitterId = userId.substring(userId.indexOf(':') + 1);
url = 'https://api.twitter.com/1.1/users/show.json?user_id=' + twitterId;
var consumerKey = process.env.MS_TwitterConsumerKey;
var consumerSecret = process.env.MS_TwitterConsumerSecret;
oauth = {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
token: identities.twitter.accessToken,
token_secret: identities.twitter.accessTokenSecret
};
}
if (url) {
var requestCallback = function (err, resp, body) {
if (err || resp.statusCode !== 200) {
console.error('Error sending data to the provider: ', err);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
} else {
try {
var userData = JSON.parse(body);
item.UserName = userData.name;
request.execute();
} catch (ex) {
console.error('Error parsing response from the provider API: ', ex);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
}
var req = require('request');
var reqOptions = {
uri: url,
headers: { Accept: "application/json" }
};
if (oauth) {
reqOptions.oauth = oauth;
}
req(reqOptions, requestCallback);
} else {
// Insert with default user name
request.execute();
}
}
});
}
You're talking about the token on the client side correct? That token is specific only to the client. If you're using Server Side flow, the server is the only one with that token. If you want to send that to the client, you need to do that via a custom API you create.
This class you're talking about does only contain those two properties. But on your server side, your ServiceUser can access the different identity provider tokens in order to speak to those servers APIs. Your linked post is correct in how you access the token, you're mistaken on where you can access that token, it's only on the server side (if you use the server directed login flow).
Here is the custom API Script I had working in Mobile Services to return the profile of the logged in user. I am working on updating to Mobile Apps as some environment variables appear to have changed. Would love to know if anyone has gotten it to work with Mobile Apps.
exports.get = function (request, response) {
var user = request.user;
user.getIdentities({
success: function (identities) {
var req = require('request');
var url = null;
var oauth = null;
var userId = user.userId.split(':')[1];
console.log('Identities: ', identities);
if (identities.facebook) {
url = 'https://graph.facebook.com/me?access_token=' +
identities.facebook.accessToken;
} else if (identities.google) {
url = 'https://www.googleapis.com/oauth2/v3/userinfo' +
'?access_token=' + identities.google.accessToken;
} else if (identities.microsoft) {
url = 'https://apis.live.net/v5.0/me?access_token=' +
identities.microsoft.accessToken;
} else if (identities.twitter) {
var consumerKey = process.env.MS_TwitterConsumerKey;
var consumerSecret = process.env.MS_TwitterConsumerSecret;
oauth = {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
token: identities.twitter.accessToken,
token_secret: identities.twitter.accessTokenSecret
};
url = 'https://api.twitter.com/1.1/users/show.json?' +
'user_id=' + userId + '&include_entities=false';
} else {
response.send(500, { error: 'No known identities' });
return;
}
if (url) {
var reqParams = { uri: url, headers: { Accept: 'application/json' } };
if (oauth) {
reqParams.oauth = oauth;
}
req.get(reqParams, function (err, resp, body) {
if (err) {
console.error('Error calling provider: ', err);
response.send(500, { error: 'Error calling provider' });
return;
}
if (resp.statusCode !== 200) {
console.error('Provider call did not return success: ', resp.statusCode);
response.send(500, { error: 'Provider call did not return success: ' + resp.statusCode });
return;
}
try {
var userData = JSON.parse(body);
response.send(200, userData);
} catch (ex) {
console.error('Error parsing response: ', ex);
response.send(500, { error: ex });
}
});
} else {
response.send(500, { error: 'Not implemented yet', env: process.env });
}
}
});
};

Login With Evernote

I'm trying to connect Evernote with Meteor.
But I'm having a really bad time, trying to get the Oauth token, I was trying to follow this example Evernote Sample Meteor, but is pretty old (2 years), but I tried to follow it and I got the idea.
I can get the connect to evernote, the login page and the email verification, my problem raised on the Meteor Method.
handleCallback, which need the "verify" param, which in this case is the
ouath_token
Second try.
On the evernote npm README they suggest to use oAuthjs, and I try with this code.
var hostName = "http://sandbox.evernote.com";
var options,oauth;
options = {
consumerKey: 'xxxxxxxxx',
consumerSecret: 'xxxxxxxxx',
callbackUrl : 'http://localhost:3000/oauth/auth',
signatureMethod : "HMAC-SHA1",
};
oauth.request({'method': 'GET', 'url': hostName + '/oauth',
'success': function(data){
console.log(data);
}, 'failure': function(data){
console.log(data);
}});
But it returns
(STDERR) No valid request transport found.
So I'm pretty stuck here.
The npm module provided by Evernote includes helper functions to get OAuth working.
Install the Evernote npm module via:
$npm install evernote
Below is the simplest single file example of implementing OAuth in a Evernote application I could put together. Just change the values of CONSUMER_KEY and CONSUMER_SECRET below and it should run just fine if you've installed Evernote:
var Evernote = require('evernote').Evernote;
var http = require("http");
var url = require("url");
CONSUMER_KEY="Put your consumer key here";
CONSUMER_SECRET="put your consumer secret here";
if (CONSUMER_KEY === "Put your consumer key here"){
console.error("\nPlease enter your Evernote consumer key and secret\n\nIf you don't have a key you can get one at:\nhttps://dev.evernote.com/#apikey\n")
process.exit(1)
}
var global = {};
global.oauthToken = '';
global.oauthSecret = '';
function getOauthVerifier(url) {
var regex = new RegExp("[\\?&]oauth_verifier=([^&#]*)"),
results = regex.exec(url);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
var handler = function(request, response) {
var params = url.parse(request.url)
var pathname = params.pathname;
console.log("Request for " + pathname + " received.");
var client = new Evernote.Client ({
consumerKey: "Put your consumer key here",
consumerSecret: "put your consumer secret here",
sandbox: true
});
if (pathname == "/"){
var callbackUrl = 'http://localhost:8888/oauth';
client.getRequestToken(callbackUrl, function(err, oauthToken, oauthSecret, results){
if(err) {
console.log(err);
}
else {
global.oauthToken = oauthToken;
global.oauthSecret = oauthSecret;
console.log("set oauth token and secret");
var authorizeUrl = client.getAuthorizeUrl(oauthToken);
console.log(authorizeUrl);
response.writeHead(200, {"Content-Type":"text/html"});
response.write("Please click here to authorize the application");
response.end();
}
});
}
else if (pathname == "/oauth"){
client.getAccessToken(
global.oauthToken,
global.oauthSecret,
getOauthVerifier(params.search),
function(error, oauthAccessToken, oauthAccessTokenSecret, results) {
if(error) {
console.log("error\n\n\n");
console.log(error);
}
else {
response.writeHead(200, {"Content-Type":"text/html"});
response.write(oauthAccessToken);
response.end();
}
}
);
}
else {
response.writeHead(200, {"Content-Type":"text/html"});
response.write("not a valid URL GO HOME ");
response.end();
}
};
http.createServer(handler).listen(8888);

Resources