Passport & SmartThings - node.js

This is going to be quite a broad question as I am stuck where to really start. I'm trying to authenticate with SmartThings using Passport. Looking at the SmartThings documentation here:
http://docs.smartthings.com/en/latest/smartapp-web-services-developers-guide/tutorial-part2.htm
SmartThings doesn't return any user information, simply an authentication token you then use to make calls to your SmartThings instance to control the environment.
I'm currently trying to use the OAuth2 Strategy, however this expects a user profile to be returned to serialise the user, which in this instance is null.
What I am trying to achieve is for someone to authorise with SmartThings and store their token in a session so that their data can be pulled.
Long term I will assign it to a user account local to my application, however for now, I'd just like to get the above working.
Does anyone know how I am best going about this. I am somewhat struggling with this.. perhaps using the OAuth2 Strategy isn't the right way to go about it? I currently have this:
var passport = require('passport');
var OAuth2Strategy = require('passport-oauth2').Strategy;
var verifyHandler = function(req, token, refreshToken, profile, done){
return done(token)
}
passport.serializeUser(function(user, done) {
done(null, user.id);
});
module.exports.http = {
customMiddleware: function(app) {
passport.use(new OAuth2Strategy({
authorizationURL: 'https://graph.api.smartthings.com/oauth/authorize',
tokenURL: 'https://graph.api.smartthings.com/oauth/token',
clientID: '123',
clientSecret: 'abc',
callbackURL: 'http://localhost:1337/auth/smartthings/callback',
skipUserProfile: true,
passReqToCallback: true
}, verifyHandler));
app.use(passport.initialize());
app.use(passport.session());
}
}

I think that what you want to do is this in the authentication process:
Authenticate the user in your application using the passport's local strategy
Manually generate SmartThings' authorization code and token - guide here
Save the token in user's session
After that you can use the token in session to make requests to SmartThings' API

Related

PassportJS with Facebook strategy, is my code correct?

I use NodeJs with passportJS in my app to allow users to login/register using Facebook. It seems to work fine, not sure if I understand fully what is happening there though. So the idea is that users can try to login from different pages in my app using Facebook details. After Facebook returns me all the details I log them in or register new user using what Facebook returned and after this is done redirect them to same page but being already logged in. The code is:
var passport = require('passport'),
FacebookStrategy = require('passport-facebook').Strategy;
function setupFBStrategy(req, res, next) {
return function(req, res, next) {
var redirectUrl = req.params.currentPage;
console.log('setupFBStrategy')
passport.use(new FacebookStrategy({
clientID: 'abc',
clientSecret: 'def',
// step 2 ################################
callbackURL: "/auth/facebook/callback?currentPage="+redirectUrl,
passReqToCallback: true,
profileFields: ['first_name', 'last_name', 'photos', 'email']
},
function(req, accessToken, refreshToken, profile, done) {
// step 5 ###########################
// verify callback. Now I have user email inside 'profile' and I authenticate this aginst my database. I use `done(..)` to further instruct my app if the registration/authentication with my system was success or not
}
));
next();
}
}
app.use(passport.initialize());
// step 1 ################################
app.get('/auth/facebook/cp/:currentPage', setupFBStrategy(), passport.authenticate('facebook', { authType: 'rerequest', scope: ['email'] }));
app.get('/auth/facebook/callback',
function(req, res, next) {
console.log(req.query.currentPage)
passport.authenticate('facebook', {
successRedirect: '/'+req.query.currentPage, // redirects when user allowed or logged in with username password
failureRedirect: '/'+req.query.currentPage // takes here when user clicks cancel when asked to give permissions
})(req,res,next);
}
);
passport.serializeUser(function(user, done) {
console.log('serialize='+user)
done(null, {});
});
passport.deserializeUser(function(user, done) {
console.log('deserialize=' + user);
done(null, {});
});
The steps are:
in my app user clicks "login/register with facebook" that makes request to auth/facebook/cp route.
route calls setUpFBStrategy. I append current page user is looking at to callbackUrl.
PassportJS send redirect back to user browser and user browser redirects to facebook for authentication.
when facebook is finished authenticating user it sends redirect to user browser so the browser redirects to callbackURL with URL specified in step 2. It also appends '?code=' querystring to callback URL. Is this querystring hashed version of what Facebook returns so in my case public info and email?
Now my server 'auth/facebook/callback' is executed and verify callback is executed. Depending if I call done(null,profile) etc inside verify callback server returns redirect to browser and browser redirects to successRedirect or failureRedirect 'successRedirect' or 'failureRedirect' routes.
All seems to work so far but is my understanding correct? Is 'code' querystring hashed version of details facebook returns? Why do I even need serializeUser and deserializeUser functions in my code? When would I use refreshToken and accessToken?
yes your code seems to be fine.
passport.serializeUser and passport.deserializeUser and function provided by the passport
passport.serializeUser is called once on login when you call
req.logIn(someValue,function(){})
here someValue is the value you want to store in the passport session
and on every request when you call req.isAuthenticated() function to check that the passport session exist or not the passport.deserializeUser will be called returning true or false.
and in end of the user browsing means on logout you call req.session.destroy to destroy that perticular users session.

Missing required parameter: redirect_uri with passport-google-oauth

Using passport-google-oauth: "0.2.0" in my MEAN Stack application (found here: https://github.com/jaredhanson/passport-google-oauth). When I run the application and attempt to sign in with a Google API this error is returned
That’s an error.
Error: invalid_request
Missing required parameter: redirect_uri
Request Details
scope=https://www.googleapis.com/auth/plus.login
response_type=code
redirect_uri=
client_id=xxxx-xxxx.apps.googleusercontent.com
The redirect param is here
passport-init.js
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var GOOGLE_CLIENT_ID = "xxx-xxx.apps.googleusercontent.com";
var GOOGLE_CLIENT_SECRET = "xxxx";
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackUrl: "http://127.0.0.1:3000/auth/google/oauth2callback" },
function(accessToken, refreshToken, profile, done){
done(null,profile); } ));
The routes are here authenticate.js
router.get('/google', passport.authenticate('google',
{ scope: ['https://www.googleapis.com/auth/plus.login']}),
function (req, res){ });
router.get('/google/oauth2callback', passport.authenticate('google', {
successRedirect: '/auth/success', failureRedirect: '/auth/failure' })
, function (req, res) {res.redirect('/');} );
I am sure I am missing something simple, but I don't know what to add in this question that will give you the best information. Please ask and I will do my best to answer you. This is what feels like the pertinent data.
Funny thing is if I add the callbackUrl manually then everything works great. I can reach the Google API fine. Then I am given the choice to "allow" or "deny" the request.
When defining the GoogleStrategy, the JSON key should be callbackURL instead of callbackUrl (i.e., capital URL). Had this 'issue' as well ;-)
I use something like that-
1. Make sure that's URL and not uri.
2. Make sure the callback URL you registered is same as the one you are requesting for.
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
// Use the GoogleStrategy within Passport.
// Strategies in Passport require a `verify` function, which accept
// credentials (in this case, an accessToken, refreshToken, and Google
// profile), and invoke a callback with a user object.
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://www.example.com/auth/google/callback"
//should be same as the one you registered in credentials.
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return done(err, user);
});
}
));
P.S:my first one on stackoverflow. please ignore mistakes and help me in improving.
I have a working example using the same strategy. Since I don't get this error, can't pinpoint what the problem is, but I wanted to suggest you check the following:
add to your google strategy creation (new GoogleStrategy({...})) the scope:
scope: 'https://www.googleapis.com/auth/userinfo.email',
Make sure your google api is configured properly in the dev api console. Specifically:
Under APIs and auth | Credentials | OAuth consent screen - all the required url.
Under APIs and auth | Credentials - look for your web api client and see you authorized all the relevant URIs. The auth will not work if the call is from or the redirection is to a page that was not listed in this section.
My issue occuors in authenticate with WSL. This error bellow is presented:
error issue
To solved , utilize the command gcloud init --console-only in your terminal.
I had this issue to. in my nestJs Application. I solved it by changing the CallbackURL from "callbackUrl" to "callbackURL" URL all caps

passportjs get users twitter credentials

I want to authenticate a user via passport's twitter strategy, but not sign the user in. All I want to do is store their credentials so I can tweet to their account at a later date, but I'm not seeing how this is possible.
It looks like you have to call the done callback which then stores the users id in the session. My user is already authenticated with my application, but wants to attach one or more twitter account that they can choose to tweet to at a later date.
Here's my Twitter strategy
passport.use(new TwitterStrategy({
consumerKey: '...',
consumerSecret: '...',
callbackURL: '/add/twitter/callback',
passReqToCallback: true
},
function(req, token, tokenSecret, profile, done) {
process.nextTick(function() {
//save the users twitter credentials for use later on and call
//my custom callback here ...
});
});
}));
I'm also using express.js so here is are my routes
router
.get('/auth/twitter', passport.authenticate('twitter'))
.get('/auth/twitter/callback',
passport.authenticate('twitter'), function(req, res) {
console.log('made it here');
// Successful authentication
res.render('manager/add-twitter', {});
});
Is it possible to have a custom callback that gets fired no matter what?
As it turns out, you can do this using authorize instead of authenticate. Here's the docs for anyone who's interested: http://passportjs.org/guide/authorize/

PassportJS - FacebookTokenStrategy returns 404

I am using PassportJS to handle FB authentication for both browser and mobile clients. For web users I am using the Passport FacebookStrategy and this is working as intended. I would also like to allow mobile clients to access my API. I am trying to use Passport FacebookTokenStrategy to facilitate this. This seems to be working with one small issue. When a mobile client makes a GET request to the server the FacebookTokenStrategy is used and the verify callback function is invoked. In the verify function I can see that the user profile is available and therefore the authentication has succeeded. However an HTTP status of 404 is sent back in the response to the mobile client. I'm not sure how to configure this properly. This is what I'm trying currently:
// Web based auth
passport.use(new FacebookStrategy({
clientID: Config.facebook.clientID,
clientSecret: Config.facebook.clientSecret,
callbackURL: "http://localhost/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate(profile, function(err, user){
done(err, user);
});
}
));
// Mobile client auth
passport.use(new FacebookTokenStrategy({
clientID: Config.facebook.clientID,
clientSecret: Config.facebook.clientID
},
function(accessToken, refreshToken, profile, done) {
console.log(profile);
User.findOrCreate(profile, function(err, user){
done(err, user);
});
}
));
// Redirect the user to Facebook for authentication. When complete,
// Facebook will redirect the user back to the application at
// /auth/facebook/callback
exports.fb_auth = passport.authenticate('facebook',{ scope: 'email' });
// Facebook will redirect the user to this URL after approval. Finish the
// authentication process by attempting to obtain an access token. If
// access was granted, the user will be logged in. Otherwise,
// authentication has failed.
exports.fb_callback = passport.authenticate('facebook', { successRedirect: '/',
failureRedirect: '/login' });
// Mobile Authentication
exports.mobile_fb_auth = passport.authenticate('facebook-token');
Should I be providing passport.authenticate('facebook-token'); with some additional 'onsuccess' callback? That makes sense in the context of a web client but I'm not sure how this should be handled using the facebook-token strategy.
I just had the same issue and was able to resolve it. The 404 is returned because of how middleware works in express. You need to pass in a third function that responds with a success.
The third function isn't called always. It's only called when the previous middleware succeeds.
apiRouter.get('/auth/facebook',
// authenticate with facebook-token.
passport.authenticate('facebook-token'),
// if the user didn't successfully authenticate with the above line,
// the below function won't be called
function(req, res){
res.send(200);
});
`

nodejs backbone and passportjs

i am using nodejs (with express) and backbone. I would like to integrate passport.js for facebook authentication.
I have the following route:
app.get('/auth/facebook', passport.authenticate('facebook', { scope: [ 'email', 'user_about_me'], failureRedirect: '/login' }), users.signin);
What should I do in case the user logged in successfully? How can I access to the user data?
What should I do in case the user DID NOT log in successfully? How can I open the facebook dialog?
Are there any good examples of using passport.js with single page applications?
I know I am answering late but in case you haven't been able to figure out how to use facebook strategy of passport yet, you can go through example provided here.
I hope this is helpful for you :)
Here is the solution recently I have done the facebook connect with passport
I assume you install the passport modules
app.js
var passport = require('passport');
require('./lib/connect')(passport); // pass passport for configuration
routes.js
// send to facebook to do the authentication
app.get('/auth/facebook',
passport.authenticate('facebook', { scope : 'email' })
);
I have created a lib file
connect.js
var FacebookStrategy = require('passport-facebook').Strategy;
module.exports = function(passport) {
passport.use(new FacebookStrategy({
clientID : facebookAuth.clientID,
clientSecret : facebookAuth.clientSecret,
callbackURL : facebookAuth.callbackURL,
passReqToCallback : true // allows us to pass in the req from our route
},
function(req, token, refreshToken, profile, done) {
// here you can get the user profile info
console.log("profile : "+JSON.stringify(profile));
// asynchronous
process.nextTick(function() {
//your logic
});
});
};

Resources