Node js を用いたTwitter Login

本文

Twitterログインを作成したかった。

passport-twitter というのが有名だったが、session が必要だった。

session 使わずに作りたかったけど、断念したので経緯をメモ。

やりたかったこと

session をサーバーに保存するのは仕様上できない。

だとすると、redis に入れるとかあるけど、それもめんどい。cookieに入れる方法もあるけど、それはそれで...

というわけで、sessionに情報を保存せずに、twitter ログインを実装したかった。

結論

Twitter ログインは、セッション(相当のもの)の利用が必須ではなかったけど、諦めて利用する方法にした。

OAuth1の仕様としては、request_token 取得時に返ってくる token_secret を sessionかどこかに保存する必要がある。

passport-twitter では、passport-oauth1 を内部で利用してる。

で、この内部で node-oauth ってライブラリでは、request_token_secret を access token 取得時に必要としており、passport-oauth1 では、これを session に入れるようにしている。

ただ、twitter-lite というライブラリを使って、自分で試したところ、この request_token_secret を access token 取得時に利用しなくても、リクエストが返ってきた。

こちらの記事によると、twitter では必要ないらしい。

Twitter Login にも CSRF 脆弱性ができやすい罠が!? - OAuth.jp

ということで、twitter ログインをするためには、セッションへの保存が必要ないが、passport-twitter を利用するなど正しい方法でOAuth1を利用する場合は必要ということが分かった。

で、そんな網の目を通すような実装をすると、後の人に怒られそうなので、今回は passport-twitter を使い、session に request_token を保存する方法で実装することにした。

ちなみに、Facebookや、Google は OAuth2 に対応してるので、そもそもこの話は当てはまらない。

TwitterAPIは OAuth2 に対応してるものとしてないものがあるから、こういう話になっている。

authentication - Why passport-twitter requires session support - Stack Overflow

といった経緯のため、まず cookie-session を利用して実装し、その後 redis利用に変更したいと考えている。

Twitter での ログインについて

TwitterAPIを叩くための認証は app auth と user auth の2種類ある。

app auth は client key と client secret だけでAPIを叩ける(これはtwitter developer tool から取得できる。)

一方、user auth は、client key, client secret に加えて、access token, access token secret が必要。

この access token を取得するには

Log in with Twitter — Twitter Developers

  1. POST oauth/request_token を叩き(この時にcallback url を設定する)、oauth_tokenを取得する。

  2. oauth_token を get query につけて、GET oauth/authenticate を開く。

  3. そうすると、twitter が callback url に oauth_token と oauth_verfier を query としてつけて遷移してくる。

  4. この oauth_token と oauth_verfier を使って、POST oauth/access_token を叩く。

  5. そうすると、oauth_token, oauth_token_secret, user_id, screen_name が返ってくるので、このoauth_tokenたちとclient key たちを利用して好きなAPIを叩く。

  6. passport-twitter では、GET account/verify_credentials を叩いて、ユーザーの情報を取得してる。

OAuth1 の仕組みを利用している。

ただ、oauth/access_tokenを叩く時に、reqest_token_secret を利用する必要がないため、そこは仕様と違うっぽい?

OAuth2 の仕組み

OAuth 2.0 の仕組みと認証方法 | murashun.jp

実際の実装

const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
const cookieSession = require('cookie-session');
const passport = require('passport');

.....

async function start() {
  app.use(cookieParser());

  // authnicate周り
  app.use(
    cookieSession({
      name: 'passport-session',
      keys: ['qwwn3io2'],
      maxAge: 60 * 5 * 1000 // 5分
    })
  );
  app.use(passport.initialize());
  app.use(passport.session());
  const authnicate = require('./router/authnicate');
  app.use('/authnicate', authnicate);
  ......
}

start();
const { Router } = require('express');
const router = Router();

const passport = require('passport');
const TwitterStrategy = require('passport-twitter').Strategy;

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

passport.use(
  new TwitterStrategy(
    {
      consumerKey: envSet.TWITTER_CONSUMER_KEY,
      consumerSecret: envSet.TWITTER_CONSUMER_SECRET,
      callbackURL: envSet.TWITTER_CALLBACK,
    },
    async (_token, _tokenSecret, profile, done) => {
      const params = {
        type: 'twitter',
        id: profile._json.id_str,
        name: profile._json.screen_name,
        image: profile._json.profile_image_url
      };
      // こうすると、session に params の情報が保存される。
      done(null, params);
    }
  )
);

// TwitterLogin
router.get('/tw', passport.authenticate('twitter'));

// TwitterLogin Callback
router.get(
  '/tw/callback',
  passport.authenticate('twitter', {
    successRedirect: '/account/social'
  })
);

// passport-session を利用すると、勝手にreq.user でsessionに登録したuserにアクセスできる。
router.get('/social_user', (req, res) => {
  if (req.user) {
    res.json(req.user);
  }
  res.status(404);
});

module.exports = router;

最後

もし間違ってたら教えて欲しいです!