Nodejsのfacebook-node-sdkを使ってGraphAPIのOAuth認証をやってみる

# 背景
Nodejs + Express + nodejs-facebook-sdk を使って OAuth 認証をしてみたかった

# 環境
- express-generator を使って Express のデフォルト環境を構築します。

```bash
$ express fb-test
$ cd fb-test
$ npm install
```

- facebook-node-sdk をインストールする

```bash
$ npm install fb --save
```

# 画面など

- Loginリンク用の画面

```jade:index.jade
extends layout

block content
    h1= title
    p Welcome to #{title}
    a(href="#{loginUrl}") #{loginUrl}
```

- Routing の定義

```js:index.js
var express = require('express');
var router = express.Router();
var FB = require('fb');
var config = require('../config');     // AppID, appSecret, redirectUrl 定義済みであること
var step = require('step');

// Facebookアプリの AppID, APPSecret は予め取得して config.js に定義しておく
// config.facebook.redirectUri に コールバック用の URL を定義しておく
// 例では https://example.com/login/callback を想定する
FB.options({
    appId: config.facebook.appId,
    appSecret: config.facebook.appSecret,
    redirectUri: config.facebook.redirectUri,
    version: 'v2.6'
});

/* GET home page. */
router.get('/', function (req, res, next) {
    var accessToken = req.session.access_token;
    if (!accessToken) {
        res.render('index', {
            title: 'Facebook Login',
            // 必要なScopeを定義しつつ、OAuth Login 用のURLを生成する
            loginUrl: FB.getLoginUrl({scope: ['user_about_me', 'publish_actions', 'user_friends']})
        });
    }
    else {
        res.render('index');
    }
});
```

**※ 注意**
Callback用のURL は Facebookアプリのダッシュボード →「Facebookログイン」→ 「有効なOAuthリダイレクトURI」に設定しておくこと

- Callback の定義

```js:index.js
router.get('/login/callback', function (req, res, next) {
    var code = req.query.code;
    step(
        function () {
            // access token 取得
            FB.napi('oauth/access_token', {
                client_id: FB.options('appId'),
                client_secret: FB.options('appSecret'),
                redirect_uri: FB.options('redirectUri'),
                code: code
            }, this);
        },
        function (err, result) {
            if (err) throw(err);

            // access token の有効期限を最大まで伸ばす
            // 2016/9 現在 60日 に設定される （今後変わる可能性があるため要調査）
            FB.napi('oauth/access_token', {
                client_id: FB.options('appId'),
                client_secret: FB.options('appSecret'),
                grant_type: 'fb_exchange_token',
                fb_exchange_token: result.access_token
            }, this);
        },
        function (err, result) {
            if (err) throw(err);

            // access token を Session に格納
            req.session.access_token = result.access_token;
            req.session.expires = result.expires || 0;

            // 自分の名前と、FacebookID 取得
            FB.napi('me', {access_token: req.session.access_token}, this)
        },
        function (err, result) {
            if (err) throw(err);
            console.log(util.inspect(result));

            // 何か次の画面表示
            res.render('NextPage');
        },
    );
});

```

# その他やってみたこと
## API で記事を投稿してみる

上記でAccessToken 取得後、なにか投稿してみる

```js:index.js
router.get('/feed', function (req, res, next) {
    var result_string = [];
    step(
        function () {
            FB.napi('me/feed', 'POST',
                {
                    message: 'TESTです',
                    access_token: req.session.access_token
                }, this);
        },
        function (err, result) {
            if (err) throw(err);
            // 何か次の画面
            res.render('NextPage');
        }
    )
});

```

これで

```text
http://example.com/feed
```

へアクセすると、投稿されます