WordPress REST APIにOAuth1.0aで認証して投稿する

WordPress REST APIで投稿するには認証が必要となる。
認証には、クッキーベース、ベーシック認証ベース、OAuth認証ベース、の方法があるが、 その中でも一番セキュアな、OAuthでの認証を行ってみる。

環境情報など

試した環境など。

  • PHP 5.6
  • WordPress ver.4.5.3
    • WP REST API ver.2.0-beta13.1
    • WP REST API – OAuth 1.0a Server ver.0.2.1
  • ドメイン : http://wprest.local

WordPressのセットアップ

WP REST API

WordPress REST API (Version 2) — WordPress Plugins
プラグインの新規追加から検索すれば出てくる。 そこからインストールして、有効化すればOK。

WP REST API – OAuth 1.0a Server

WP-API/OAuth1: OAuth server implementation for WP API
上記からzipをダウンロードし、プラグイン->新規追加からzipをアップロードし、その後有効化する。

ユーザー項目に、Applicatonsが増えていれば正しく有効化出来ている。
また、WP REST APIを追加していれば、/wp-json/にアクセスした際にOAuth認証するためのURLが表示されるようになる。

1
2
3
4
5
6
7
8
authentication: {
  oauth1: {
    request: "http://wprest.local/oauth1/request",
    authorize: "http://wprest.local/oauth1/authorize",
    access: "http://wprest.local/oauth1/access",
    version: "0.1"
  }
},

アプリケーションの追加

ユーザー -> Applicationsを開き、Add Applicationをクリック。それぞれの項目を適当に入力する。 Callbackの値は適当に/testなどと入れておいた。
本来であれば、承認が行われた後にcallbackで指定されたURLへリダイレクトがかかるはずなのだが、不具合なのか動作しなかった。

Add ConsumerをクリックするとClient KeyClient Secretが生成される。

項目 内容
Client Key RY5OpVfznCzY
Client Secret 8HHflSELMukNNE6NxFNFeJDAsoHA7Dhjkb6wXFoxduMykAwo

PHPで接続

環境変数

環境変数に上記で取得したアプリケーションのキーなどを追加して使用することにする。

1
2
WP_CLIENT_KEY=RY5OpVfznCzY
WP_CLIENT_SECRET=8HHflSELMukNNE6NxFNFeJDAsoHA7Dhjkb6wXFoxduMykAwo

PECL oauth

Oauth 1.0aでの認証を行うために、PECL oauthライブラリを使用する。
公式のマニュアル: PHP: OAuth – Manual

PECL::OAuthは、OAuthコンシューマやプロバイダの機能をphpで手軽に実装できるようにする拡張モジュールです。 http://blog.flatlabs.net/20100611_062745/

HerokuでPHPの拡張モジュールを利用する場合には、composerで追加する事が出来る。 以下のコマンドで追加が可能。

1
$ composer require ext-oauth

参考: Heroku PHP Support | Heroku Dev Center

ローカル環境などのサーバに追加する場合は、直接インストールしてやる必要がある。
参考: PECL/oauthの導入方法 | 配電盤

今回はローカル環境には、Scotchboxを利用しているので、Ubuntuにインストール方法をメモしておく。

インストールと設定

上記参考サイトの通りだが、そのままoauthをインストールしようとするとバージョンでエラーが出る。 oauthの最新版では、PHP7.0以上のみサポートされているようなので、PHP5.6対応のバージョンを明示的に指定してやる必要がある。

1
2
$ sudo apt-get install apache2 php5 php5-dev php-pear libpcre3-dev make
$ sudo pecl install oauth-1.2.3

最後に書かれている通り、php.iniに追記する。
/etc/php5/apache2/php.ini

1
extension=oauth.so

apache再起動。

1
$ sudo service apache2 restart

phpinfoでOAuthが有効と表示されていれば完了。

トークンの取得

今回の承認などに必要なPHPファイルは全て同一ドメイン・同一階層に置くものとする。

OAuth1.0aの承認フローなどの動きは以下がとても参考になった。

参考: WP REST API の OAuth 認証の方法と何が起こっているのかとなぜそんなことをしているのか – Shinichi Nishikawa's

コード

参考 : Tumblr API OAuth認証の方法(PHPサンプル付き) – Qiita

こちらのコードをほぼそのまま利用させてもらった。

login.php

1
2
3
4
5
6
7
8
9
10
<?php
require_once './OAuthSample.php';

$oauth_sample = new OAuthSample();
try {
    // リクエストトークンの取得とリダイレクト開始
    $oauth_sample->goToAuthorize();
} catch (\Exception $e) {
    // エラー処理
}

OAuthSample.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?php
/**
 * Tumblr OAuth認証実装サンプル
 *
 * @author newton
 */
class OAuthSample
{
    const REQUEST_TOKEN_URL  = 'http://wprest.local/oauth1/request';
    const AUTHORIZE_URL      = 'http://wprest.local/oauth1/authorize';
    const ACCESS_TOKEN_URL   = 'http://wprest.local/oauth1/access';

    public $CONSUMER_KEY = '';
    public $CONSUMER_SECRET = '';

    /**
     * コントストラク
     * セッションの初期化をやる
     */
    public function __construct()
    {
        $this->CONSUMER_KEY = getenv('WP_CLIENT_KEY');
        $this->CONSUMER_SECRET = getenv('WP_CLIENT_SECRET');

        if (!isset($_SESSION)) {
            session_start();
        }
    }

    /**
     * リクエストトークンの取得~リダイレクト
     */
    public function goToAuthorize()
    {
        $oauth = new \OAuth($this->CONSUMER_KEY, $this->CONSUMER_SECRET);
        // リクエストトークン取得
        $request_token = $oauth->getRequestToken(self::REQUEST_TOKEN_URL);

        if (!$request_token) {
            throw new Exception('リクエストトークンの取得に失敗');
        }

        // リクエストトークンをセッションに保存する
        $_SESSION['request_token'] = $request_token['oauth_token'];
        $_SESSION['request_token_secret'] = $request_token['oauth_token_secret'];

        $params = ['oauth_token' => $request_token['oauth_token']];
        $path = self::AUTHORIZE_URL . '?' . http_build_query($params);

        $this->redirect($path);
    }

    /**
     * アクセストークンの取得
     * コールバック後にコールされる用
     *
     * @return array アクセストークンのセットされたハッシュ
     */
    public function getAccessToken()
    {
        $oauth = new \OAuth(self::CONSUMER_KEY, self::CONSUMER_SECRET);
        // アクセストークンの取得
        $oauth->setToken($_SESSION['request_token'], $_SESSION['request_token_secret']);
        $access_token = $oauth->getAccessToken(self::ACCESS_TOKEN_URL, $_GET['oauth_verifier']);

        if (!$access_token) {
            throw new \Exception('アクセストークンの取得に失敗');
        }

        return $access_token;
    }

    /**
     * リダイレクト
     *
     * @param string $path   リダイレクト先URL
     * @param int    $status ステータスコード
     */
    private function redirect($path, $status = 302)
    {
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
        header("Location: {$path}", true, $status);
        exit;
    }
}

callback.php

1
2
3
4
5
6
7
8
9
10
11
<?php
require_once './OAuthSample.php';

$oauth_sample = new OAuthSample();
try {
    // アクセストークンの取得
    $access_token = $oauth_sample->getAccessToken();
    var_dump($access_token);
} catch (\Exception $e) {
    // エラー処理
}

承認

作成したlogin.phpへアクセスすると(ログインしていない場合はログイン画面が表示されログイン後に)承認のページが表示される。

Authorizeをクリックすると、許可されて、承認コードが表示される。 (ここでコードが表示されるのではなく、コールバックURLへリダイレクトが行われるのが通常のフローだと思う)

Your verification token is j0lHiEOe07gOtUOkEA6J1q00

アクセストークンの取得

コールバックが自動で行われないので、作成したcallback.phpへ直接アクセスしてやる。

http://wprest.local/callback.php?oauth_verifier=j0lHiEOe07gOtUOkEA6J1q00

こうすることで、アクセストークンを取得できた。

1
2
3
4
5
6
array(2) {
  ["oauth_token"]=>
  string(24) "UTriXsugNS1c0ddCc1UBuMPj"
  ["oauth_token_secret"]=>
  string(48) "6GAHfovkjdSPm2LZbtf06vV3ouBML8WaqiwPIfCGsGY0jVHA"
}

実際に投稿などをPOSTするには、アプリケーションのカスタマーキーなども合わせて必要になる。 まとめると以下となる。

項目 内容
Client Key RY5OpVfznCzY
Client Secret 8HHflSELMukNNE6NxFNFeJDAsoHA7Dhjkb6wXFoxduMykAwo
OAuth Token UTriXsugNS1c0ddCc1UBuMPj
OAuth Token Secret 6GAHfovkjdSPm2LZbtf06vV3ouBML8WaqiwPIfCGsGY0jVHA

投稿

さて、ここまででアクセストークンなど投稿に必要なものが一通り揃ったので、ようやく新規投稿の準備が整った。 投稿は簡単で、今までと同じようにトークンなどをセットして指定のエンドポイントへパラメータを投げてやるだけでおyい。
エンドポイントは、新規投稿となるので、http://wprest.local/wp-json/wp/v2/postsとなる。
これも、先ほどのTumblerへの投稿を書いた記事を参考にさせてもらった。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

$consumer_key = 'RY5OpVfznCzY';
$consumer_secret = '8HHflSELMukNNE6NxFNFeJDAsoHA7Dhjkb6wXFoxduMykAwo';
$oauth_token = 'UTriXsugNS1c0ddCc1UBuMPj';
$oauth_token_secret = '6GAHfovkjdSPm2LZbtf06vV3ouBML8WaqiwPIfCGsGY0jVHA';
$response = '';

try {
    $oauth = new \OAuth($consumer_key, $consumer_secret);
    $oauth->setToken($oauth_token, $oauth_token_secret);
    //POST
    $params = ['title' => 'From PHP'];
    $oauth->fetch('http://wprest.local/wp-json/wp/v2/posts', $params, OAUTH_HTTP_METHOD_POST);
    $response_info = $oauth->getLastResponseInfo();
    if ($response_info['http_code'] == 201) {
        $response = json_decode($oauth->getLastResponse(), true);
    }else{
        throw new \Exception('記事の投稿に失敗');
    }
} catch (\Exception $e) {
    // エラー処理
    var_dump($e);
}
// 結果をダンプ
var_dump($response);

これでこのファイルへアクセスすると、無事、新規投稿が行われる。 以上。

   このエントリーをはてなブックマークに追加