0

I am trying to use everyauth within express to authenticate users to a website that allows adding text commentary to images. I am currently using the twitter oauth api to authenticate my users.

Now I'm trying to established a custom user database that allows me to keep multiple ways of logging in connected to a single entry in a CouchDB. I am running into trouble when i want to add a new user to the DB when he initially connects via twitter. The code of my findUserById reads as following:

everyauth.everymodule.findUserById (userId, callback) ->  
    users.findById userId, (err,res) ->
        if res.id    
        # id returned, so there is an entry in the DB
            callback null, res
        else         
        # no entry in the DB, add a new one
            users.saveById JSON.stringify(userId), {"name":"test"}, (saveErr, saveRes) ->
                callback null, saveRes

everyauth.twitter
    .consumerKey(config.twitterConsumerKey)
    .consumerSecret(config.twitterConsumerSecret)
    .findOrCreateUser((session, token, secret, user) ->
         promise = @.Promise().fulfill user
    ).redirectPath '/'

findById and saveById are methods of a cradle object that query the DB, userId is provided by everyauth, as it seems.

My problem lies in the {"name":"test"} part. This is the location where I want to add the data from the req.session.auth.twitter object to the DB. How can I access those values from within the findUserByIdfunction?

Is that even possible? Is there a different approach? I am looking at the findOrCreateUser function, but I have no idea how to change that without crashing my app - i do not yet grasp the concept of the Promise.

arvidkahl
  • 852
  • 8
  • 15

2 Answers2

1

I can't provide any guidance on how to solve your issue using everyauth. However, have you considered using Passport for authentication?

I'm the developer of Passport, so feel free to ask me any questions. I wrote it after trying out everyauth and being similarly frustrated by the flow control offered, including promises.

Passport has a simple mechanism for handling sign in using Twitter (or any other OAuth provider), using the passport-twitter module:

passport.use(new TwitterStrategy({
    consumerKey: TWITTER_CONSUMER_KEY,
    consumerSecret: TWITTER_CONSUMER_SECRET,
    callbackURL: "http://127.0.0.1:3000/auth/twitter/callback"
  },
  function(token, tokenSecret, profile, done) {
    User.findOrCreate({ twitterId: profile.id }, function (err, user) {
      return done(err, user);
    });
  }
));

Within the verify callback (as its known), you have complete access to the token and tokenSecret issued by Twitter, as well as the full Twitter profile. You can use that information to find or create a user in your database.

Triggering sign in is as simple as adding a couple routes to your app:

app.get('/auth/twitter', passport.authenticate('twitter'));

app.get('/auth/twitter/callback', 
  passport.authenticate('twitter', { successRedirect: '/',
                                     failureRedirect: '/login' }));
Jared Hanson
  • 15,940
  • 5
  • 48
  • 45
  • Thank you for the detailed explanation. I was indeed just as confused by the Promise part and from what i read, that sort of paradigm was left behind by node. But passport looks very promising, i will use it in my next big project :) – arvidkahl Mar 17 '12 at 21:18
0

After fiddling around further, I have found a solution to the problem i posed. To access the full user data that is transmitted with the OAuth request with respect to the Promise-structure of everyauth, the everyauth.twitter call should look like this:

everyauth.twitter
 .consumerKey(config.twitterConsumerKey)
 .consumerSecret(config.twitterConsumerSecret)
 .findOrCreateUser((session, token, secret, user) ->
   users.findByTwitterId user.id, (err,res) ->
     if res.id
       user=res.value
     else
       newUser = {id:user.id,name:user.name,twitter:user}
       user = newUser
       users.saveById JSON.stringify(user.id), user, (saveErr, saveRes) -> 
   promise = @.Promise().fulfill user
 ).redirectPath '/'

The findByTwitterId call is a function that queries the CouchDB for a view looking up documents that contain a twitter.id field.

The req.user object is populated by this:

everyauth.everymodule.findUserById (userId, callback) ->  
 users.findByTwitterId userId, (err,res) ->
    if res.id
        callback null, res.value
    else
        callback null, null
arvidkahl
  • 852
  • 8
  • 15