Problems with OAuth on node.js - javascript

I am trying to get OAuth to work on node.js. I found this in the documentation of node-oauth:
var OAuth= require('oauth').OAuth;
var oa = new OAuth(requestUrl,accessUrl,consumerKey,consumerSecret,"1.0A",responseUrl,"HMAC-SHA1");
The next step in the official tutorial says:
"Then get hold of a valid access token + access token secret as per the normal channels"
What are these "normal channels"?
I know that the user has to authenticate somehow on the "vendor" site and that by some way a response url is called, but I can't find a description how to implement this. Can someone enlighten me?

I'm not sure what OAuth service you are trying to connect to so I'll just use twitter as an example. After you create your OAuth object you need to first request an oauth token. When you get that token, then you need to redirect to, for twitter, their authenticate page which either prompts them to login, then asks if it's ok for the app to login.
oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){
if (error) new Error(error.data)
else {
req.session.oauth.token = oauth_token
req.session.oauth.token_secret = oauth_token_secret
res.redirect('https://twitter.com/oauth/authenticate?oauth_token='+oauth_token)
}
});
When you first created the OAuth object, you set a responseURL, or the callback url. It can be anything, for my app its just /oauth/callback. In that callback you receive the oauth verifier token. You then use both the oauth request token and oauth verifier token to request the access tokens. When you receive the access tokens you will also receive anything else they pass, like their username.
app.get('/oauth/callback', function(req, res, next){
if (req.session.oauth) {
req.session.oauth.verifier = req.query.oauth_verifier
var oauth = req.session.oauth
oa.getOAuthAccessToken(oauth.token,oauth.token_secret,oauth.verifier,
function(error, oauth_access_token, oauth_access_token_secret, results){
if (error) new Error(error)
console.log(results.screen_name)
}
);
} else
next(new Error('No OAuth information stored in the session. How did you get here?'))
});
Hope this helps! I had the same problems when I started on this.

The access token is issued to your application after walking the user through the "OAuth dance" (as its affectionately known). This means obtaining a request token and redirecting the user to the provider (Twitter, in this case) for authorization. If the user grants authorization, Twitter redirects the user back to your application with a code that can be exchanged for an access token.
node-oauth can be used to manage this process, but a higher-level library will make it much easier. Passport (which I'm the author of), is one such library. In this case, check out the guide to Twitter authentication, which simplifies the OAuth dance down to a few lines of code.
After that, you can save the access token in your database, and use it to access protected resources in the usual manner using node-oauth.

An update to post tweet to user timeline:
#mattmcmanus, Extending #mattmcmanus nice answer, I would like to post a tweet to timeline. For this, I am using the same code as mattcmanus given above.
Step 1:
oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){
if (error) new Error(error.data)
else {
req.session.oauth.token = oauth_token
req.session.oauth.token_secret = oauth_token_secret
res.redirect('https://twitter.com/oauth/authenticate?oauth_token='+oauth_token)
}
});
Step 2:
app.get('/oauth/callback', function(req, res, next){
if (req.session.oauth) {
req.session.oauth.verifier = req.query.oauth_verifier
var oauth = req.session.oauth
oa.getOAuthAccessToken(oauth.token,oauth.token_secret,oauth.verifier,
function(error, oauth_access_token, oauth_access_token_secret, results){
if (error) new Error(error){
console.log(results.screen_name)
}else{
// NEW CODE TO POST TWEET TO TWITTER
oa.post(
"https://api.twitter.com/1.1/statuses/update.json",
oauth_access_token, oauth_access_token_secret,
{"status":"Need somebody to love me! I love OSIpage, http://www.osipage.com"},
function(error, data) {
if(error) console.log(error)
else console.log(data)
}
);
// POST TWEET CODE ENDS HERE
}
}
);
} else
next(new Error('No OAuth information stored in the session. How did you get here?'))
});
I have added oauth_access_token & oauth_access_token_secret in commented code. This will post a tweet update to user's timeline. Happy tweeting!!!

Related

How can I get AWS credentials using a SAML token?

What I am trying to do: Authenticate my users using ADFS, pass the SAML response token to AWS and get back credentials which I can then use to access AWS resources.
What I am able to do now: Sign in successfully through ADFS and get the SAML token back which confirms the successfully sign in.
What is not working: Calling the AWS.STS.assumeRoleWithSaml functions gets a 403 Access Denied error
How it works thus far:
Users click a button on my application, which calls the following:
var RPID = encodeURIComponent('urn:amazon:webservices');
var result = 'https://virtualMachine.eastus.cloudapp.azure.com/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=' + RPID;
window.location.href = result;
A successful sign in here returns back to the application a SAML response token
var saml = new URL(window.location.href);
var token = saml.searchParams.get('SAMLResponse');
The application then calls assumeRoleWithSAML to get back credentials. The Principal ARN refers to the identity provider I am trying to access and the RoleARN refers to a role which has full access to everything:
authenticateSAMLwithCognito(token) {
//define our security token service object
var sts = new AWS.STS();
//build our parameter object
var params = {
//cognito identity provider
PrincipalArn: 'arn:aws:iam::accountid:saml-provider/wmpo-adfs',
//role assuming
RoleArn: 'arn:aws:iam::accountid:role/ADFS-Dev',
//authorization
SAMLAssertion: token
}
console.log("Parameters sent", params);
sts.assumeRoleWithSAML(params, (err, data) => {
if(err) console.log(err);
else console.log("Success!", data);
})
}
However the response from this exchange is:
I am really unsure why this is, but if anyone has some helpful pushes that would be great! Thanks and happy new year
Wow that only took days, but though I was constantly stumbling, I finally made it to the point I was trying to get.
The answer was in the same credentials get function that I used when I authenticated users through a username password combo by way of a Cognito User Pool.
authenticateThroughCognito(token) {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-west-2:IdentityPoolId',
Logins: {
'arn:aws:iam::accountId:saml-provider/wmpo-adfs' : token
}
});
(AWS.config.credentials as AWS.Credentials).get((err) => {
if(err) console.log(err);
else {
console.log("Success");
console.log(AWS.config.credentials);
}
})
}

How to configure Amazon AssumeRoleWithWebIdentity for access token in Ionic 3 project?

I'm little bit confuse using AssumeRoleWithWebIdentity method.
let me describe step by step.
Step 1:-I get the facebook token from facebook.
Step 2:-using getId method, I get the IdentityId from amzon cognito.
Step 3:-used getOpenIdToken and passed the IdentityId I get the {IdentityId,Token} in response.
(Question 1: Can I access the amazon services using this token?)
Step 4:- Then I'm trying to implement AssumeRoleWithWebIdentity method
using the params:-
params = {
RoleArn: arn:aws:iam::XXXXX:role/XXXXX,
RoleSessionName: 'XXXX',
WebIdentityToken: 'XXXX'
DurationSeconds: 3600,
ProviderId: 'www.amazon.com'
};
let sts = new AWS.STS();
sts.assumeRoleWithWebIdentity(params, function (err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
})
Question 2:-WebIdentityToken ,I have to use which one the provided by the facebook or by the cognito in return of getOpenIdToken method.
Question 3:- ProviderId, I am trying to logged in using facebook is it will be graph.facebook.com or www.amazon.com?
Question 4: When I am using WebIdentityToken as provide by getOpenIdToken in response and ProviderId as www.amazon.com I'm getting InvalidIdentityToken: Provided Token is not a Login With Amazon token
Question 5:- When I am using WebIdentityToken as provide by facebook and ProviderId as graph.facebook.com I'm getting AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
If it's right how to give access please tell step by step
Your end goal seems to be to obtain temporary AWS credentials for your app users. You do not need to interact with AssumeRoleWithWebIdentity for this. Amazon Cognito Federated Identities directly vends AWS credentials and hides all the STS interactions.
As explained in authentication flow documentation, you need to interact with GetId and GetCredentialsForIdentity APIs and your app user will directly get temporary AWS credentials.
As for answer to your Question 3, no the OpenId token vended by GetOpenIdToken cannot be used with AWS APIs directly. For detailed explanation, you can refer to this answer.

Auth0 email confirmation, how to handle registration gracefuly

I am using auth0.
My app requires users to confirm their email.
When a user registers, he receives this alert:
Error: unauthorized. Check the console for further details.
This is because the user has not yet verified his email.
How do I "catch" this event / alert in order to redirect the user to a view of my choice?
Thank you for your help
There is a couple of different parts to this.
1). have you enabled the email verified rule? (it is a template available from Auth0 dashboard -
function forceEmailVerification(user, context, callback) {
console.log("force-email-verification");
if(context.connection !== "MyDB") {
return callback(null, user, context);
}
if (!user.email_verified) {
return callback(new UnauthorizedError('Please verify your email before logging in.'));
} else {
return callback(null, user, context);
}
}
That effectively raises an exception in the Rules pipeline if email not verified. It will return the error to your application on the callbackUrl you provide as two query params - error and error_description. It is then up to you how you handle this - Here is a sample Node.js application I wrote specifically to illustrate how this works - In the sample, i am using some express middleware to check for the error and error_description and forward to a Custom controller / view if detected.
2). Only if needed, you can also explicitly trigger an email verification email. It is a POST request to https://{{tenant}}.auth0.com/api/users/{{user_id}}/send_verification_email
endpoint, passing an Authorization Bearer header with an Auth0 APIv1 token (and empty body). The token can be obtained by making a POST request to https://{{tenant}}.auth0.com/oauth/token endpoint passing body of the form:
{
"client_id": "{GLOBAL CLIENT ID}",
"client_secret": "{GLOBAL CLIENT SECRET}",
"grant_type": "client_credentials"
}
You can get the global client id and client secret under account settings -> advanced from Auth0 dashboard. Please do NOT store any secrets on SPA apps etc - using this endpoint should only be done from Client Confidential / Trusted applications (e.g traditional MVC webapp you own).
Hope this helps. Please leave comments if anything unclear.

How to get LinkedIn API access token without a redirect

I'm trying to use LinkedIn's API to access Universities LinkedIn pages to periodically collect how many followers they have. This seems doable, but I cant seem to generate an access token without having some weird redirect URL that has to take you to a GUI login page!
I'm using node.js for this, specifically this package: https://www.npmjs.org/package/node-linkedin
I have a API key and secret, so all I need is a access token then I'll be set to actually start using their API routes.
var Linkedin = require('node-linkedin')('KEY', 'SECRET', 'callback');
var linkedin = Linkedin.init('my_access_token'); // need a token to initialise!
Any ideas?
Edit: Here's my code so far:
var Linkedin = require('node-linkedin')('KEY', 'SECRET', './oauth/linkedin/callback');
app.get('/oauth/linkedin', function(req, res) {
// This will ask for permisssions etc and redirect to callback url.
Linkedin.auth.authorize(res, ['r_basicprofile', 'r_fullprofile', 'r_emailaddress', 'r_network', 'r_contactinfo', 'rw_nus', 'rw_groups', 'w_messages']);
});
app.get('/oauth/linkedin/callback', function(req, res) {
Linkedin.auth.getAccessToken(res, req.query.code, function(err, results) {
if ( err )
return console.error(err);
/**
* Results have something like:
* {"expires_in":5184000,"access_token":". . . ."}
*/
console.log(results);
var linkedin = Linkedin.init(result);
return res.redirect('/');
});
});
What you are trying to do is an application-only authentication, it seems linkedIn has removed this option unlike facebook and twitter. As from now it is only possible to authenticate as a user.
If you really want to skip the redirect you could use something like PhantomJS which is a headerless browser. But i strongly recommend you not to do so as LinkedIn requires a user to authenticate in their license agreement. I don't know if it is legal but you could provide yourself an end-point which you use to generate the authentication_code and access_token and then save it to a database (60 days valid by default).

Ongoing Access to Google Calendar API

How do I request access to a user's calendar once, then query events without having to request access again? Is there an access key that can grant continuous access as long as it isn't revoked?
I am currently using the google-calendar module in a nodejs app running express + mongodb.
The example below shows partial code for making the OAuth request and redirecting back to the app. This works great. What I want though is once I have access, to be able to query the user's events any time I want. This will be used in a booking app which, once a user registers their public Google Calendar, allows others to see their availability.
I have looked at the Google Calendar API documentation, but I can't figure out what is needed for the ongoing access I need.
Configuration:
var GoogleCalendar = require('google-calendar');
var google_calendar = new GoogleCalendar.GoogleCalendar(config.google.clientId, config.google.clientSecret, 'http://localhost:3000/authentication');
Display route:
app.get('/display', function(req, res) {
// redirect user to Google Authentication
var access_token = req.session.access_token;
if(!access_token) {
req.session.authReturn = req.url;
return res.redirect('/authentication');
}
google_calendar.listCalendarList(access_token, function(err, calendarList) {
// do something with the calendar events...
}
...
Authenticate route:
app.all('/authentication', function(req, res){
// Redirect the user to Google's authentication form
if(!req.query.code){
google_calendar.getGoogleAuthorizeTokenURL(function(err, redirectUrl) {
if(err) return res.send(500,err);
return res.redirect(redirectUrl);
});
}
// Get access_token from the code
else {
google_calendar.getGoogleAccessToken(req.query, function(err, access_token, refresh_token) {
if(err) return res.send(500,err);
req.session.access_token = access_token;
req.session.refresh_token = refresh_token;
return res.redirect(req.session.authReturn);
});
}
});
Use the Oauth 2.0 offline access parameter. See details at:
https://developers.google.com/accounts/docs/OAuth2WebServer#offline

Categories