I'm trying to Implement Twitter login in my NodeJS app.
As per the documentation from Twitter, I need to pass the below parameters to this url via POST request.
URL:
https://api.twitter.com/oauth/request_token
PARAMETERS:
oauth_nonce=,
oauth_signature=,
oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="currentTimestamp",
oauth_consumer_key=“myKEY”,
oauth_version="1.0"
I'm passing a random string for oauth_nonce parameter. I'm not clear on how to create a oauth_signature?
I keep getting 215 error whenever I make the POST request beacuse of incorrect oauth_nonce and oauth_signature values I guess.
How do I generate oauth_nonce and oauth_signature values while making the request in NodeJS.
Those parameters need to be passed in your authorization header:
OAuth oauth_nonce="K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw",
oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1300228849",
oauth_consumer_key="OqEqJeafRSF11jBMStrZz",
oauth_signature="Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D",
oauth_version="1.0"
But before that, you need to get a signature, which will then give you all of the parameters above. Check the documentation here.
A recommendation would be to use a 3rd party library like passport, which heavily simplifies this process if needed.
To answer your question:
How do I generate oauth_nonce and oauth_signature values while making the request in NodeJS.
Going through these post will be of help to you Creating a signature and How to generate an OAuth nonce.
Twitter makes a whole lot of sense if used correctly. I have seen some tutorials that has been quite useful to those around me, that I feel maybe you might want to check Node Authentication: Twitter and Implementing Sign in with Twitter for Node.js
Or you might want to check passportjs
You will have to install it in your project by running:
npm install passport-twitter
Configuration
const passport = require('passport')
, TwitterStrategy = require('passport-twitter').Strategy;
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://www.example.com/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
User.findOrCreate(..., function(err, user) {
if (err) { return done(err); }
done(null, user);
});
}
));
This Github repo might be a great reference to you.
If you're using reactjs, this (npm i react-twitter-auth) might be useful to you too.
can't comment, that's why answering here.
the docu sais, oauth_nonce:
is a unique token your application should generate for each unique request
it is like the salt of the encryption. you can find oauth_signature under the same link. how to generate it is described here.
Finally I could get Access Token using this library
Related
I'm working on an Ionic application.
On the one hand I have an auth basic form in which people fill in their username and password. On the other hand I'd like to implement authentification with JSON Web Tokens and Node JS.
The workflow would be this one : as soon as a user fills in his credentials, they will be sent with a POST request. If these credentials are correct, the user can access to the application and gets an access token as a response.
The thing is that I'm a little bit lost with all that concepts. I built a form and sent informations with a POST request. I managed to create some APIs with Node JS and that's ok. I see how to build a authentified webservice too (e.g : https://github.com/jkasun/stack-abuse-express-jwt/blob/master/auth.js).
But I concretely don't understand the links between the html form and the authorisation check part..
To be clearer, how is it possible to make the html part and the Node JS scripts communicate together ?
Before posting that question I made many researches and found many stuff on building an authentified API. But there was very few advice on how to make it communicate with the client part (I mean the form), which is what I have to do.
If anyone has any ressources (document, Github examples..) on that, I'll greatly appreciate. But I would be very happy too if someone try to make me understand these concepts. I guess I have to improve my knowledge on all that so that I could test some POCs.
Many thanks in advance !
JWT General flow:
1- Authenticate using a strategy (You done it)
2- Deliver an accessToken along with response (You done it)
3- The client MUST store this accessToken (LocalStorage is the best place, not cookies: They are vulnerable to csrf attacks)
4- On every request you are going to make to a protected area (where user is supposed to be authenticated and authorized), make sure to send you accessToken along with it, you can put it on Authorization header, a custom header, directly in body of the request... Basicaly just make sure to send it properly.
5- On the server receiving client requests, you NEED to verify that token (You verify it by checking the signature of the accessToken).
6- If he is authorized, great, if not, send back an HTTP Unauthorized Error.
Here is my implementation using an accessToken on a header + passportjs-jwt:
Client code
To store token:
localStorage.setItem('accessToken', myAccessToken);
To send it:
const myAccessToken = localStorage.getItem('accessToken');
{
headers: {'Authorization', `Bearer ${myAccessToken}`}
}
Server code
1- Configure passport
passport.use('jwt', new JwtStrategy({
jwtFromRequest: jwtPassport.ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: myAccessTokenSecret,
passReqToCallback: true
}, (req, payload, done: (err?, user?) => void): void {
User
.findOne({where: {id: req.params.id}})
.then((user: User) => {
if (!user) {
return done(new Error(`No user found with id: ${req.params.id}`), null);
}
return done(null, user);
})
.catch((e: Error) => done(e, null));
}));
Pay attention to callback: If your callback is called, it means that passport has successfuly verified the token (It is valid). In my example, i get the user details in database and this is the user that will be returned and put in req.user object passed to my controller below:
2- Finally, the controller route (protected area):
.get('/users/:id', passport.authenticate('jwt'), (req, res, next) => {
// do stuff in protected area.
}
And that's it. If you want more security, check refreshTokens implementation.
I used passport because i found it relevant in my case, but you can write your own handler, by using jsonwebtoken and just calling its "verify" function.
You can find documentation of passport jwt strategy here => http://www.passportjs.org/packages/passport-jwt/
I have implemented passport with GitHub-Strategy. Here's the Glith.
It works wonderfully and I'm receiving the user-profile on redirect from GitHub.
Now, I'm only trying to understand how this actually works 'under the hood'.
I did not find any similar question here on stackoverflow, neither on Passport.
So if I open Chrome Developer Tools during the Auth-Flow, the following seems to be going on when I click on Login with GitHub:
the node route /auth/github is called
node redirects to https://github.com/login/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Frightful-exclusive-carriage.glitch.me%2Fauth%2Fgithub%2Fcallback&client_id=ccfcc73fac8223317176
the user is presented with GitHub-Login-Page
User types in GitHub-credentials and clicks 'Login'
GitHub checks the credentials
If valid credentials are provided, user is authenticated and GitHub redirects to the registered callback-endpoint, which is in my case: https://rightful-exclusive-carriage.glitch.me/auth/github/callback
The callback-url has a url-parameter, e.g. ?code=02337a951c242b9202fd. It's interesting to note, that it's a GET-method and nothing else is provided.
On the server, the passport.authenticate('github', ...) method is called inside of the /auth/github/callback-route.
When the GithubStrategy is instanciated, a callback-function is passed with the signature function(accessToken, refreshToken, profile, cb). Somehow magically, the accessToken and profile are fully available here. And I don't understand how this happens.
How is passport receiving the profile?
Is node.js making a server-side call to GitHub? Maybe with the ?code=<id> ?
Yeah that is exactly what NodeJS is doing. This doesn't have anything to do with Passport.JS or Node.JS. It is the OAuth mechanism of how authorizations work.
Whenever a the Identity provider like twitter/facebook calls your /callback with a ?code= query param It then hits another url and gets the AccessToken, RefreshToken and Idtoken(which is basically the user profile).
You can check out in the source code as well:
In this strategy.js#L157 and strategy.js#L173 of passports oauth strategy:
if (req.query && req.query.code) {
....
self._oauth2.getOAuthAccessToken(code, params,
function(err, accessToken, refreshToken, params) {
....
}
....
}
And the oauth2.js#L177 and oauth2.js#L190 of node-oauth package can see that:
exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) {
...
this._request("POST", this._getAccessTokenUrl(), post_headers, post_data, null, function(error, data, response) {
....
})
}
Bascially a POST request is being sent to the accessTokenUrl.
I am writing Oauth using Exchange client. I have registered my app at apps.dev.microsoft.com. I am using JavaScript with Node.js. To perform the Oauth, I have used passport with several different strategies, but none of them seem to work for me. Some of them were missing profile information, and this last one I am using does not return me the access token. I have debugged the lib, but I don't know what I am doing wrong. Here is the lib I am using:
https://github.com/Azure-Samples/active-directory-node-webapp-openidconnect.
I am using the OIDC strategy.
So this returns a profile obj but access and refresh token is "undefined".It does return a authorization 'code' to make the token request. Redirect url, and all other meta data is fine such as:
prompt: 'login',
response_mode: 'query',
state: true,
authorizationURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
tokenURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
Also, client ID , client secret and callbackURL are correct.
Did I miss something essential in the process or MSFT oauth with passport is broken?
As passport SDK doesn’t store accessToken and refreshToken in user profile. So we can modified sdk file to get tokens.
We can find these code in node_modules/passport-azure-ad/lib/passport-azure-ad/oidcstrategy.js begin in line 176 :
log.info('TOKEN RECEIVED');
log.info('Access Token: ' + accessToken);
log.info('');
log.info('Refresh Token: ' + refreshToken);
log.info('');
log.info(params);
log.info('----');
And we can find profile is defined in line 229 and 265. for easy use, we can directly add the tokens in the profile, for example, below code var profile = {}; we add profile.accessToken = accessToken;.
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.