OpauthでYahooJPのOAuth認証を行う

Yahoo Japanが提供するWeb APIにはOAuthで認証され、払い出されたトークンを必要とするものがあります。
ここではYahooから提供しているOpauthのライブラリーを使いトークンの取得を行います。

:::note alert
2022年4月27日に「Yahoo! ID連携 v1」はクローズされる予定とのことです。
https://developer.yahoo.co.jp/changelog/2021-08-03-yconnect1.html
:::

# Yahooアプリケーション作成

Yahooのアプリケーションにはv1とv2があり「Yahoo ID連携 v1」を選択してください。このライブラリーはv2には対応していません。
また、ここのアプリケーションIDとシークレットをリクエストを送る際の引数にセットします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29324/90d8e4f7-7804-0ba8-2ff9-7f3be643e389.png)

コールバックは以下のような設定です。1行目は必ず書かなければならないURLで、リクエストを送ったパスと同じ階層の`oauth2callback`というURLです。理由は後述する処理フローに記述します。2行目は実際にコールバックするURLです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29324/3355cb92-4358-80ff-ecd5-ed7a60c1c078.png)

# 必要なもの
- Git
- Composer
- PHP

(面倒ですが手動でダウンロードすれば、GitとComposerは無くてもできます。)

# 手順
1. `opauth`をインストールします。
1. `opauth-yahoojp`をインストールします。
1. `opauth.conf.php.default`をコピーして編集します。
1. `.htaccess`を作成します。
1. `Opauth`クラスを`new`し、認証リクエストを送ります。
1. 以下のようなYahooのユーザー情報がsessionに設定されます。sessionにはトークンが含まれています。

```:$_SESSION
array(1) {
  ["opauth"]=>
  array(3) {
    ["auth"]=>
    array(5) {
      ["provider"]=>
      string(7) "Yahoojp"
      ["uid"]=>
      string(26) "SLO5VW7K6I34YQ3CZVF4AIV474"
      ["info"]=>
      array(3) {
        ["name"]=>
        string(0) ""
        ["email"]=>
        string(24) "XXXXXXXXXX@yahoo.co.jp"
        ["email_verified"]=>
        int(1)
      }
      ["credentials"]=>
      array(2) {
        ["token"]=>
        string(2196) "トークン文字列"
        ["expires"]=>
        string(25) "2020-07-12T14:31:39+00:00"
      }
      ...
  }
}
```

## ファイル構成

この構成で話を進めていきます。

```:ディレクトリ構成
|-composer
|  |-composer.json
|  |-composer.lock
|  |-vendor
|     |-composerでインストールしたファイル群
|
|-src
   |-auth
      |-yahoojp
      |  |-.htaccess
      |  |-opauth.conf.php
      |  |-authentication.php
      |
      |-callback.php
```

## opauthをインストール

`composer.json`を作成します。

```json:composer.json
{
    "require":{
        "opauth/opauth": "*"
    }
}
```

`composer.json`と同じディレクトリで`install`します。
install後、composer.lockとvenderディレクトリが作成されます。

```shell
$ composer install
```

## opauth-yahoojpをインストール

opauthをインストールしたディレクトリに移動し、`git clone`します。
e.g. /composer/vendor/opauth/opauth/lib/Opauth/Strategy

```shell
$ cd /composer/vendor/opauth/opauth/lib/Opauth/Strategy
$ git clone git://github.com/ritou/opauth-yahoojp.git Yahoojp
```

## opauth.conf.php.defaultを編集

opauthのexampleの中にopauth.conf.php.defaultというファイルがあるので、コピーします。
e.g. /composer/vendor/opauth/opauth/example/opauth.conf.php.default

```shell
$ cp /composer/vendor/opauth/opauth/example/opauth.conf.php.default /src/auth/yahoojp/opauth.conf.php
```

コピーしたファイルを編集します。

- yhoojpディレクトリまでのパスをセットします。
- security_saltはデフォルト値のままだと警告が出るのでランダム値にしました。
- アプリケーションの「アプリケーションID」と「シークレット」を設定します。

```PHP:opauth.conf.php
$config = array(
-    'path' => '/',
+    'path' => '/auth/',
    'callback_url' => '{path}callback.php',
-    'security_salt' => 'LDFmiilYf8Fyw5W10rx4W1KsVrieQCnpBzzpTBWA5vJidQKDx8pMJbmw28R1C4m',
+    'security_salt' => random_bytes(64),
    'Strategy' => array(
+        'Yahoojp' => array(
+            'client_id' => 'アプリケーションID',
+            'client_secret' => 'シークレット'
+        )
    ),
);
```

## .htaccessを作成

opauthのexampleの中の.htaccessをコピーし、編集します。
e.g. /composer/vendor/opauth/opauth/example/.htaccess
この.htaccessによって、`domain/auth/yahoojp`以下のリクエストは全て`authentication.php`へ書き換えます。

```
$ cp /composer/vendor/opauth/opauth/example/.htaccess /src/auth/yahoojp/.htaccess
```
```apache:.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
-   RewriteRule ^(.*)$ index.php [QSA,L]
+   RewriteRule ^(.*)$ authentication.php [QSA,L]
</IfModule>
```

## 認証リクエストを送る

Opauthクラスを`new`すると、認証処理が開始します。

```php5:authentication.php
<?php
$root = dirname(dirname(__DIR__));
require_once $root . '/composer/vendor/autoload.php';
require_once "./opauth.conf.php";

new Opauth($config);
```

## トークンがセッションにセットされる

認証処理が開始すると、YahooJPのログイン画面に遷移します。そこでパスワードなど入力して認証されると、引数の`callback_url`に設定した`callback.php`へコールバックされます。
セッションには、トークン(token)と有効期限(expires)がセットされています。

```php5:callback.php
<?php
session_start();

echo('<pre>');
var_dump($_SESSION);
echo('</pre>');
```

# 処理のフロー

処理の流れは公式ページにあるように3つの手順があります。
[アクセストークンの取得方法（v1）](https://developer.yahoo.co.jp/webapi/shopping/help.html#accesstoken)
このライブラリーは`new`するとこの手順を全て行ってくれます。

1つ目の「Authorizationエンドポイント」にリクエストする」時に、GETパラメータの`redirect_uri`に`oauth2callback`をセットします。これがYahooアプリケーションのコールバックURLにこのURLをセットする理由です。

# おまけ 動的にコールバックURLを設定する

上記のようにリダイレクトが発生するため、Opauthを`new`する時に、引数の`callback_url`に任意の値をセットしても、`oauth2callback`にリダイレクトされた時は、セットした任意の`callback_url`は失われデフォルトの`{path}callback.php`にコールバックされてしまいます。
そのため、動的にコールバックURLを指定するにはクッキーやセッションにセットしておくのがよいと思います。

```PHP5:authentication.php
<?php
$root = dirname(dirname(__DIR__));
require_once $root . '/composer/vendor/autoload.php';
require_once "./opauth.conf.php";

if($_GET["callback"]) // 例えば、`authentication.php`のGETパラメータにコールバックURLをセットしておきます。
{
    setcookie("yahoo_callback", $_GET["callback"]); // クッキーに保存します。
}

if($_COOKIE["yahoo_callback"])
{
    $config["callback_url"] = $_COOKIE["yahoo_callback"]; // クッキーのコールバックを引数にセットします。
}

new Opauth($config);
```