Why can't I use credentials to make followup oauth call - node.js

I am using passport-freshbooks to authenticate and retrieve a token and tokenSecret. However, when I try to use those with a separate OAuth object, I get a 401 authentication failed error.
The strategy used by passport-freshbooks uses the same oauth library, and the call to "post" is identical to the followup call (at least it looks the same to me, but maybe I'm missing something obvious).
Here's some of the pertinent code from the passport strategy:
OAuth = require('oauth').OAuth //This is called from within require('passport-oauth').OAuthStrategy
...
this._oauth = new OAuth('https://' + options.subdomain + '.freshbooks.com/oauth/oauth_request.php',
'https://' + options.subdomain + '.freshbooks.com/oauth/oauth_access.php',
freshbookDao.config.apiSubdomain,
freshbookDao.config.oauthSecret,
"1.0",
null,
"PLAINTEXT",
null,
options.customHeaders);
...
log.info("Calling userProfile with " + token + " and " + tokenSecret);
...
this._oauth.post(url, token, tokenSecret, post_body, post_content_type, function (err, body, res) {...}
I try to use that same token and tokenSecret later. I'm creating a new OAuth object, but setting it with the identical settings passed to the passport strategy. Here's some code from that:
OAuth = require('oauth')
...
oauth = new OAuth.OAuth(
'https://' + options.subdomain + '.freshbooks.com/oauth/oauth_request.php',
'https://' + options.subdomain + '.freshbooks.com/oauth/oauth_access.php',
exports.config.apiToken,
exports.config.oauthSecret,
'1.0',
null,
'PLAINTEXT');
...
log.info("Calling listInvoices with " + token + " and " + tokenSecret);
...
oauth.post(url, token, tokenSecret, body, 'application/xml', function(err, data, res) {...}
These look the same to me. However, the first one passes, and the second fails with this response:
{"statusCode":401,"data":"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<response xmlns=\"http://www.freshbooks.com/api/\" status=\"fail\">\n <error>Authentication failed.</error>\n <code>20010</code>\n</response>\n"} <code>20010</code>\n</response>\n"}
What is it that I'm doing wrong? I've included to "log.info" lines to show that I've compared the token and tokenSecret, and they are indeed the same. What is it I'm missing?

glad you're getting use out of passport-freshbooks!
I didn't write the OAuth code in it. I copied this from Jared Hanson's passport-linkedin module, then tweaked it to work with Freshbooks
If you're getting different outputs, then one of two things is happening:
1) Either you're sending different inputs, or
2) there is a different internal state.
For 1) try logging requests to a file and see what happens: Logging in express js to a output file?
is your app sending different requests?
For 2) I don't know the OAuth protocol well enough to debug it. Just enough to use it. It may be that you can't reuse the tokens on a different connection? I can't say for sure.
Hope that helps Todd!

Related

How to handle JWT token on the client site in Node.js application?

I am implementing JWT tokens for authentication.
I am not using any client-site framework like Angular or React. It is just EJS.
Step 1. I have an API developed that on successful login returns the token as shown on the picture below(I am using Postman for testing API):
API response with JSON
Step 2. I am then accessing the restricted route and passing along the Authorization header with token value, by inputing it manually in the Postman and it works just fine.
My question is WHERE and HOW do I save the returned token from the step 1 on the client, so that it is sent in the header on step 2.
I am novice to web-development and following the tutorials, but all the tutorials I found about implementing the JWT token are written for Angular or React when it comes to the client site.
Any help would be greatly appreciated.
Thank you!
First you must create the token with JWT :
const token=jwt.sign({
userId: user._id
},config.secret, {expiresIn: '24h'});
res.json({success:true,message:'Success', token:token, user: {username:user.username}});
Then in your front youcan save it into the localStorage
This will generate a unique key that you can implement in your header
After that in your routes when you want to check if there's a JWT in the header just make :
router.use((req,res,next)=>{
const token=req.headers['authorization'];
if(!token){
res.json({success:false, message:"No token provided"});
}
else{
jwt.verify(token, config.secret, (err,decoded)=>{
if(err){
res.json({success:false,message:"Token invalid: " + err});
}
else{
req.decoded=decoded;
next();
}
});
}
});
This is a middleware that will check if there's a JWT key in "authorization" header
Note that every route coming after this one are going to run this middleware.
Here You 'll find every details about JSON Web Tokens
EDIT
Here's how you could do with an AJAX request:
$("submit").click(function(){
$.ajax({
url : 'api/login,',
type : 'POST',
data : {login: $('#login').val(),password:$('#password').val()}
dataType : 'JSON',
success : function(data, statut){
localStorage.setItem('token',data.token) // assuming you send a json token
},
error : function(resultat, statut, erreur){
// whatever code you want
},
complete : function(resultat, statut){
}
});
});
Have an object where you store the token, if you want to keep the token after the user leaves so that he will remain connected as long as the token is valid, you can save it in the localStorage.
And when doing AJAX requests on client side, retrieve the token from your object of from localStorage and set the token in the Authorization header.

How to sign a cookie manually using cookieParser?

For the sake of testing, I need to provide a signed cookie with HTTP request. So that, my Express app server can consider it as a signed cookie and put it into req.signedCookies object.
However I cannot find a appropriate method in docs.
I'd like to do the following:
let signed = cookieParser.signYourCookie({ cookieName: 'cookieValue' }, secretString);
// => cookieName=cookieValue.9PuJzypXeGq3tc2fFvlukjgNZ518jk
That is an operation opposite to cookieParser.signedCookie(str, secret) method. ExpressJS does it automatically under the hood, but there is a need to sign a cookie manually sometimes and the method seems missing.
To explain why I need this. I use Chai-http and need to set a cookie with the request. And I need it to be a signed cookie, so my server could find it it req.signedCookies object:
chai.request('http://foo.com')
.get('/url/path')
.set('my-signed-cookie', 'value-of-my-signed-cookie')
The plugin doesn't have public methods for that. Which is odd, actually. So I pulled the piece from plugin's code.
Do in your app:
var crypto = require('crypto');
function sign(val, secret){
return val + '.' + crypto
.createHmac('sha256', secret)
.update(val)
.digest('base64')
.replace(/=+$/, '');
};
// Pay attention to `s:` prefix. With that, plugin considers it as a signed cookie, apparently
.set('cookie', 'my-signed-cookie=s:' + sign('value-of-my-signed-cookie', 'my-cookie-secret'))
// Is equivalent to
.set('cookie', 'my-signed-cookie=s:value-of-my-signed-cookie.Dq+0CW44ZLfvzVWqEZEcK51X6auKaz771jFy4Zs4lWk')

How to call Management API v2 to send verification mail from within a rule?

I'm writing a rule in Auth0 to trigger a verification email if a certain condition is met. To make the example small I have included the code which I am using to send the verification mail (I have removed out the unwanted code).
var url = 'https://myname.au.auth0.com/api/v2/jobs/verification-email';
var token = 'Bearer {{token}}'; //This is where the problem is how do I get the token
var userId = user.user_id;
request.post({
url: url,
headers: {
Authorization: 'Bearer {{token}}',
},
json: {
"user_id": user.user_ID
},
timeout: 5000
},
function(err, res, body) {
console.log(err);
console.log(res);
});
In the body I get the following error
{ statusCode: 400,
error: 'Bad Request',
message: 'Bad HTTP authentication header format',
errorCode: 'Bearer' }
I guess I need to pass in the access token or something like that in the header. How do I get this done?
I also saw the following article (https://auth0.com/docs/email/custom), however I'm not sure what secretToken is?
Starting from the bottom, the article (https://auth0.com/docs/email/custom) is aimed at users that want additional flexibility and use their own custom email handling. The secretToken on that example it's just to illustrate a possible - and very simple - way that their own custom email API could validate that they were being called from Auth0; in conclusion it would work almost as an API key.
If you only need to trigger a verification email through the system provided by Auth0 you're using the correct approach (Management API v2). You have more than one way to obtain a token that allows you to call this API:
Using the client credentials grant
Using the Auth0 Management API v2 Explorer
The second option would be the easiest to get started, but do take in consideration that there's a deprecation notice for that one.
Once you obtain the token, you also need to correctly pass it to the API. The code you showed may be only sample code, but make sure that you don't end up including the Bearer scheme twice, more specifically var token = 'Bearer {{token}}'; should instead just be var token = '{{token}}'; and then you would use the token variable when creating the HTTP header.
Just created the below empty rule that will get called when user tries to login and email is not yet verified and it works like a charm :D
function (user, context, callback) {
if (!user.email_verified) {
console.log("User is: " + user.user_id);
var ManagementClient = require('auth0#2.6.0').ManagementClient;
var management = new ManagementClient({
token: auth0.accessToken,
domain: auth0.domain
});
var new_userobj = {user_id:user.user_id};
management.sendEmailVerification(new_userobj,callback(new UnauthorizedError('Please click on the link in the email we have sent you to continue to login.')));
} else {
return callback(null, user, context);
}
}
I received the same error when using the wrong token, though for a different api call. I recreated your issue by using a user's access_token obtained by calling {{api-audience}}users/{{user_id}}. That token should look something like this: A1bCd2efg34IJkl5
Try using a client's access_token obtained by making this call:
curl --request POST \
--url https://{{domain}}/oauth/token \
--header 'content-type: application/json' \
--data '{
"client_id":"{{client_id}}",
"client_secret":"{{client_secret}}",
"audience":"{{audience}}",
"grant_type":"client_credentials"
}'
That token will be a full JWT.

nodejs request.post (user, pass) and get data from another url after auth

I want to get some data that are available after authentication. I pass through a post login and password on the page http://site.domain.com/auth.html and I want to get html from another page http://site.domain.com/anotherpage.html
request.post({followAllRedirects: true, url:'http://site.domain.com/auth.html', form:{user:'login#domain.com', pass:'password'}},
function (error, response, body) {
if (!error) {
request('http://site.domain.com/anotherpage.html', function(error, response, html){
fs.appendFileSync('log.txt', html, encoding='utf8');
});
}
});
Authentication takes place normally (there is a message in the html with greeting), after request I get the data as if the authentication is not passed.
fixed result:
var j = request.jar(); var request = request.defaults({jar:j});
and then my code
Most often than not, in the web, authentication information is store as cookies in the user's browser. Because this is a server request, I don't think two "unrelated" requests is going to cut it, as no header information pertaining to the first request is being sent along with the second request. Perhaps you could try this strategy or some other similar procedure to mimic that header interaction.
I found a solution, I put in top of my code, these lines
var j = request.jar(); var request = request.defaults({jar:j});
jar - If true, remember cookies for future use (or define your custom cookie jar;

Facebook example not working in Connect-auth/Express

I am following the example at facebook Connect-auth exemple. I don't understand how to get this example working.
In this snippet of code taken from the previous link:
// Method to handle a sign-in with a specified method type, and a url to go back to ...
app.get('/signin', function(req,res) {
req.authenticate([req.param('method')], function(error, authenticated) {
if(authenticated ) {
res.end("<html><h1>Hello Facebook user:" + JSON.stringify( req.getAuthDetails() ) + ".</h1></html>");
}
else {
res.end("<html><h1>Facebook authentication failed: " + error + " </h1></html>");
}
});
});
I do not understand what this does [req.param('method')] mean? It it hard to understand how connect-auth and facebook work together. I keep getting authentication failed.
The first argument to authenticate is an array of authentication strategies to try, in this example the req.param['method'] is set in the URL (var sign_in_link further down in the code) to "facebook" which matches the one and only authentication strategy initialized in the use.

Resources