Passport.js の Typetalk 用 Strategy を作った話

## 概要

Passport.js の Typetalk 用 Strategy として [passport-typetalk](https://github.com/is2ei/passport-typetalk) を作ったので紹介する記事です。

## 前提知識

Typetalk って何？という方は [こちら](https://www.typetalk.com)

## Passport.js とは？

http://www.passportjs.org/
> Passport is authentication middleware for Node.js. Extremely flexible and modular, Passport can be unobtrusively dropped in to any Express-based web application.

[jaredhanson](https://github.com/jaredhanson) という方が作った Node.js 製の認証用のミドルウェアです。Omniauth の Node.js 版みたいなやつと思ってます。

## Strategy って何？

Passport.js にはプラグイン機構があり、認証を行いたいサービスに対応したプラグインを使用することでいわゆる「Facebook でログイン」のような仕組みを手軽に実装することができます。今回、僕が作った [passport-typetalk](https://github.com/is2ei/passport-typetalk) は Typetalk の OAuth2 認証に対応した Strategy となります。

## 使い方

1) Typetalk でアプリケーションを登録します。
https://typetalk.com/my/develop/applications/register

<img width="907" alt="Screen Shot 2019-02-03 at 2.40.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/27079/745b35b1-0cff-1d4b-7826-da1fc63808f0.png">


| 入力項目 | 値 |
|---------|---|
| アプリケーション名 | passport-typetalk test |
| Grant Type | Authorization Code |
| ホームページ URL | http://localhost:3000 |
| リダイレクト URI | http://localhost:3000/auth/typetalk/callback |

登録すると、ID などが発行されます。

2) 環境変数を設定します。

```shell
$ export TYPETALK_CLIENT_ID=XXXXXXXXXXX # Client ID の値を使ってください
$ export TYPETALK_CLIENT_SECRET={YOUR_TYPETALK_TOPIC_ID} # トピックの ID を記載します。
```

3) サンプル用のサーバを実装します。

```shell
$ touch passport-typetalk.js
```

サンプルコード

```javascript
const TypetalkStrategy = require("passport-typetalk").Strategy,
    config = require("./config"),
    express = require("express"),
    passport = require("passport");

var app = express(),
    port = 3000;

passport.use(new TypetalkStrategy({
    "callbackURL": "http://localhost:3000/auth/typetalk/callback",
    "clientID": process.env.clientID,
    "clientSecret": process.env.clientSecret,
    "scope": [
        "my",
        "topic.read"
    ]
}, (accessToken, refreshToken, profile, cb) => cb(null, profile)));

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

passport.deserializeUser(function deserializeUser (obj, cb) {
    cb(null, obj);
});

app.use(require("morgan")("combined"));
app.use(require("cookie-parser")());
app.use(require("body-parser").urlencoded({"extended": true}));
app.use(require("express-session")({
    "resave": true,
    "saveUninitialized": true,
    "secret": "keyboard cat"
}));

app.use(passport.initialize());
app.use(passport.session());

app.get("/", (req, res) => {
    res.send('<a href="/auth/typetalk">Login with Typetalk</a>');
});

app.get("/profile", (req, res) => {
    res.send(`<p>ID: ${req.user.id}</p><p>Name: ${req.user.name}</p>`);
});

app.get(
    "/auth/typetalk",
    passport.authenticate("typetalk")
);

app.get(
    "/auth/typetalk/callback",
    passport.authenticate("typetalk", {"failureRedirect": "/"}),
    (req, res) => {
        res.redirect("/profile");
    }
);

app.listen(port);
```

4) サーバを起動します。

```
$ node passport-typetalk.js
```

5) http://localhost:3000 にアクセスします。

6) "Login with Typetalk" をクリックします。

<img width="145" alt="Screen Shot 2019-02-03 at 2.43.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/27079/7228b127-acd9-cc5d-c2c6-9b586c4c2c69.png">

7) "許可" をクリックします。

<img width="1237" alt="Screen Shot 2019-02-03 at 2.43.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/27079/2d970a4a-4fd4-1b9a-1246-85763340a7f7.png">

8) 認証が完了し、ユーザ情報が表示されます。

<img width="115" alt="Screen Shot 2019-02-03 at 2.43.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/27079/b4958b63-59f3-7d39-0e25-1fe548357b37.png">


---

手順は以上となります。いかがだったでしょうか？フィードバック歓迎です :pray: