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 に対応してるので、そもそもこの話は当てはまらない。
Twitter の APIは OAuth2 に対応してるものとしてないものがあるから、こういう話になっている。
authentication - Why passport-twitter requires session support - Stack Overflow
といった経緯のため、まず cookie-session を利用して実装し、その後 redis利用に変更したいと考えている。
Twitter での ログインについて
Twitter の APIを叩くための認証は 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
POST oauth/request_token を叩き(この時にcallback url を設定する)、oauth_tokenを取得する。
oauth_token を get query につけて、GET oauth/authenticate を開く。
そうすると、twitter が callback url に oauth_token と oauth_verfier を query としてつけて遷移してくる。
この oauth_token と oauth_verfier を使って、POST oauth/access_token を叩く。
そうすると、oauth_token, oauth_token_secret, user_id, screen_name が返ってくるので、このoauth_tokenたちとclient key たちを利用して好きなAPIを叩く。
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;
最後
もし間違ってたら教えて欲しいです!