技術日誌

野球関係のサービスを個人開発しています。

React/NodeJS/Passportでtwitterログインを実装してみた

こちらの記事をベースにしてReactJS/NodeJSのシステムにtwitterログインを組み込んでみた。 qiita.com

主に異なるのは型指定が緩めななんちゃってtypescriptを使っているところか。

蓋々交換機能

cap-baseball.com f:id:ckoshien:20200414202745j:plain

技術的なこと

passport-config.ts

export default function passportConfig() {
  var TWITTER_CONSUMER_KEY = "*****";
  var TWITTER_CONSUMER_SECRET =   "*******";
  var passport = require("passport"),
    TwitterStrategy = require("passport-twitter").Strategy;

  // Sessionの設定
  passport.serializeUser(function (user, done) {
    done(null, user);
  });
  passport.deserializeUser(function (obj, done) {
    done(null, obj);
  });

  passport.use(
    new TwitterStrategy(
      {
        consumerKey: TWITTER_CONSUMER_KEY,
        consumerSecret: TWITTER_CONSUMER_SECRET,
        callbackURL: "https://********/auth/twitter/callback",
      },
      function (token, tokenSecret, profile, done) {
        passport.session.user = profile;

        // tokenとtoken_secretをセット
        profile.twitter_token = token;
        profile.twitter_token_secret = tokenSecret;
        process.nextTick(function () {
          return done(null, profile);
        });
      }
    )
  );
}

auth.ts

NodeJSでtwitter認証からのコールバックなどを担当するコントローラ。

import * as express from "express";
import * as session from 'express-session'; 
import { Request } from "./interface/express.Request";
const passport = require("passport");

export class Auth{
    public router: express.Router;
    constructor() {
        this.router = express.Router();
        this.router.get("/twitter", passport.authenticate('twitter'));
        this.router.get("/twitter/success", this.success);
        this.router.get("/twitter/callback",
                passport.authenticate('twitter', 
                    { successRedirect: 'https://******/api/v2/auth/twitter/success',
                      failureRedirect: 'https://******/' })
        )}

   
    private success(req:Request,res:express.Response):void{
       if(req.session.passport !== undefined){
        res.json(req.session.passport.user.username);
       }else{
           res.sendStatus(401);
       }
    }
}

express.Requestインターフェースの拡張

import * as Express from 'express';
export interface Request extends Express.Request {
 session:any;
}

app.ts

import { Auth } from './auth';
import * as session from 'express-session';
import passportConfig from './passport-config';
passportConfig();
const passport = require("passport");

app.use(passport.initialize()); 
app.use(passport.session()); 
app.use(
  session({
    secret: '********',
    resave: false,
    saveUninitialized: false,
    cookie:{
      httpOnly: true,
      secure: true,
      maxage: 1000 * 60 * 30
    }
  })
);

ReactでNodeJS/Passportから認証情報を受け取る

credentialsオプションが必要。

  const response = await fetch('/auth/twitter/success',
  {
    method:'GET',
    credentials: "include",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
      "Access-Control-Allow-Credentials": true
    }
  });

認証が終わったタイミングで認証情報を受け取る

認証のためのウインドウを開き、 そのウインドウが閉じられたタイミングで親の画面をリロードする。 リロードの際に認証情報を受け取っている。

onClick={()=>{
                    const authWindow = window.open('/auth/twitter','newTab');
                    var timer = setInterval(function() { 
                        if(authWindow.closed) {
                            clearInterval(timer);
                            window.location.reload();
                        }
                    }, 1000);
                }}