title: Sign in Twitter OAuth without Sessions aka token_secret (AngularJS Fail)
body: <p>This is an express route from <a href="https://github.com/sahat/satellizer/blob/master/examples/server/node/server.js#L571" rel="noreferrer">angularjs satellizer example</a>, implementing 3 legged OAuth with Twitter:</p>
  
  <pre><code>/*
   |--------------------------------------------------------------------------
   | Login with Twitter
   |--------------------------------------------------------------------------
   */
  app.get('/auth/twitter', function(req, res) {
    var requestTokenUrl = 'https://api.twitter.com/oauth/request_token';
    var accessTokenUrl = 'https://api.twitter.com/oauth/access_token';
    var authenticateUrl = 'https://api.twitter.com/oauth/authenticate';
  
    if (!req.query.oauth_token || !req.query.oauth_verifier) {
      var requestTokenOauth = {
        consumer_key: config.TWITTER_KEY,
        consumer_secret: config.TWITTER_SECRET,
        callback: config.TWITTER_CALLBACK
      };
  
      // Step 1. Obtain request token for the authorization popup.
      request.post({ url: requestTokenUrl, oauth: requestTokenOauth }, function(err, response, body) {
        var oauthToken = qs.parse(body);
        var params = qs.stringify({ oauth_token: oauthToken.oauth_token });
  
        // Step 2. Redirect to the authorization screen.
        res.redirect(authenticateUrl + '?' + params);
      });
    } else {
      var accessTokenOauth = {
        consumer_key: config.TWITTER_KEY,
        consumer_secret: config.TWITTER_SECRET,
        token: req.query.oauth_token,
        verifier: req.query.oauth_verifier
      };
  
      // Step 3. Exchange oauth token and oauth verifier for access token.
      request.post({ url: accessTokenUrl, oauth: accessTokenOauth }, function(err, response, profile) {
        profile = qs.parse(profile);
  
        // Step 4a. Link user accounts.
        if (req.headers.authorization) {
          User.findOne({ twitter: profile.user_id }, function(err, existingUser) {
            if (existingUser) {
              return res.status(409).send({ message: 'There is already a Twitter account that belongs to you' });
            }
            var token = req.headers.authorization.split(' ')[1];
            var payload = jwt.decode(token, config.TOKEN_SECRET);
            User.findById(payload.sub, function(err, user) {
              if (!user) {
                return res.status(400).send({ message: 'User not found' });
              }
              user.twitter = profile.user_id;
              user.displayName = user.displayName || profile.screen_name;
              user.save(function(err) {
                res.send({ token: createToken(user) });
              });
            });
          });
        } else {
          // Step 4b. Create a new user account or return an existing one.
          User.findOne({ twitter: profile.user_id }, function(err, existingUser) {
            if (existingUser) {
              var token = createToken(existingUser);
              return res.send({ token: token });
            }
            var user = new User();
            user.twitter = profile.user_id;
            user.displayName = profile.screen_name;
            user.save(function() {
              var token = createToken(user);
              res.send({ token: token });
            });
          });
        }
      });
    }
  });
  </code></pre>
  
  <p>The problem is Step 3:</p>
  
  <pre><code>   var accessTokenOauth = {
        consumer_key: config.TWITTER_KEY,
        consumer_secret: config.TWITTER_SECRET,
        token: req.query.oauth_token,
        verifier: req.query.oauth_verifier
      };
  
      // Step 3. Exchange oauth token and oauth verifier for access token.
      request.post({ url: accessTokenUrl, oauth: accessTokenOauth });
  </code></pre>
  
  <p>Because the <a href="https://github.com/request/request#oauth-signing" rel="noreferrer">node-request</a> documentation describes Step 3 as:</p>
  
  <pre><code> // step 3
    // after the user is redirected back to your server
    var auth_data = qs.parse(body)
      , oauth =
        { consumer_key: CONSUMER_KEY
        , consumer_secret: CONSUMER_SECRET
        , token: auth_data.oauth_token
        , token_secret: req_data.oauth_token_secret
        , verifier: auth_data.oauth_verifier
        }
      , url = 'https://api.twitter.com/oauth/access_token'
      ;
    request.post({url:url, oauth:oauth}
  </code></pre>
  
  <p>The difference is, in the satellizer example, it doesn't pass <code>token_secret</code> to sign-in, but it should. So is this a mistake or what am I missing?</p>
  
  <p>The real problem for me was, 3 legged twitter sign-in flow actually requires <code>session</code> on server side, but the <code>satellizer</code> example doesn't use any sessions, so I was wondering how this possible without sessions, but either it is not possible and satellizer example is wrong, or I don't understand something.</p>