Laravel + Vue.js でOauth認証を利用したサンプルSPA構築 [4] Oauthサーバの実装

以下を参考に、実装を進めます。
https://readouble.com/laravel/5.7/ja/passport.html

Laravel Passportを使ってみます。
このライブラリはOAuthサーバーとして有名なleague上に構築されているとのこと。
https://oauth2.thephpleague.com/

なお、Laravelのインストールとデフォルトのユーザー認証構築済みの前提。

インストール

composerでインストール

composer require laravel/passport

client, accessTokenを格納するテーブル作成

php artisan migrate

accessToken生成のためのキーを作成

php artisan passport:install

Userモデルへ、traitの追加。

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

AuthServiceProviderへメソッドを追加。
AccessTokenの発行・失効をこれで管理するよう。
/oauth/authorizeなど一通り使えるURLがこれで設定されるとのこと。

AuthServiceProvider.php

use Laravel\Passport\Passport;

public function boot()
{
  Passport::routes();
}

設定ファイルで、認証APIリクエストの方式を変更。

config/auth.php

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

APIテスト

APIのテストをしてみます。
ひとまず今はパスワードグラントのテスト。

Chrome addonのRestlet Client が便利。
https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm

まずは、/register でユーザー登録をしておきます。

次にクライアントを登録。
grant typeはpasswordとなるので、以下の様に生成。

php artisan passport:client --password

成功すると、ID&secretが表示される。

Password grant client created successfully.
Client ID: 2
Client Secret: r5V5xoKmBrU2kOmG4ZOrF0iCcJ4lfVncTvWnRk2P

Request Token

アクセストークンを取得する。
トークンの有効期間は、AuthServiceProvider で設定した内容となる。

Method: POST
URL: youredomein.com/oauth/token
Header: [Content-Type: application/json;]
body:

{
    "grant_type": "password",
    "client_id": 2,
    "client_secret": "r5V5xoKmBrU2kOmG4ZOrF0iCcJ4lfVncTvWnRk2P",
    "username": "my.name@mail.com",
    "password": "test",
    "scope": "*"
}

Result:

{
"token_type": "Bearer",
"expires_in": 1296000,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjgwYjU2MWQyZDkyNDYyMTFjMTEwZjRhZTBlMGU1NjhjMTE5M2FmMTg4YWE1YTNlYmEzNzdkMGMyMzdmYzhiYjNmYTY0NmRkZGQwZWUxZWJiIn0.eyJhdWQiOiI2IiwianRpIjoiODBiNTYxZDJkOTI0NjIxMWMxMTBmNGFlMGUwZTU2OGMxMTkzYWYxODhhYTVhM2ViYTM3N2QwYzIzN2ZjOGJiM2ZhNjQ2ZGRkZDBlZTFlYmIiLCJpYXQiOjE1MzgxMjMzNDMsIm5iZiI6MTUzODEyMzM0MywiZXhwIjoxNTM5NDE5MzQzLCJzdWIiOiIxIiwic2NvcGVzIjpbIioiXX0.YC1eGzgFzdKtOrIhz2a6mlGeGIwKEC3Fdn2edmC4NWmujT09kLCRz2yKykpS_sgZkOUV34FQyZxU2Wh3CXd89Bdqk2x-Vn_w3sggw2GbJMkkFY_pLFdUpFXdUJoNBE-tExvL4wPSQy9kmwgY0KP5Ufpg25y8g5jG9Nog2AnJihA_iRI-f07JpLGIcYO1xmXwyPZMT1JsDe_BKjqH4CQLOkMHI9JtMdr8Sghrg5uoOoFdfDcRT2Sm8AvMNcQ-NIdG6vLApY2hsOAPEXhc0XBIE6qjERwP1gtg0qZq0hIGY3fWKKo7q935M9CpBd-TRIQHSGcMdkBoSpLAnRla0avUqzkj3Mwkw6OvK6CPdB80rRU9cPU5Z1p3Ta6kCSL74PwLs3dTXgLdXxY-W6k3SBc9KbLWRkojcmxHYGKzfuYn4Ax3EQc0JXfwch0qTlP5OPeWRnBlGE147tla5Gyp6wobB8oTo3GYFh4TnRiF-fleMF4dUStp_0f8swo3jlrynhydzUPXhtgH2pRGKqsWNPgyPpZrGkUYgUfWrfQw1hxjNMDD_w61HyNgk5vCPfJgioBkOUqKkbVXvuGliMiOirFPptizkktXfHLBo_1eP2glruWmicg35ajwIxCmN7NcbiSszR96ZOmCCrJYlok5yiMtbdvY9YCiwTCu8W5E5HXZAT8",
"refresh_token": "def502006646396ea837409159a9869ef64072f2d3ae436d2c91746ed0ec72f72cb6721c03c2e48d165f2e76f8b3fec4a5e78c46d9fb25686a5200aa8699138d52a25cd03ab0d922a2bec8432430e2bfd94881c8bb663ab5e41cf1dddf0c9ff31ff277e950ebe51559c6ee9db53546fbd481cbc6f4814a664d0eca7e6508cb1b2e7530bb9dfbc908ceda042c4b31d2a6d577d70bc3dba5e5b7c903a5a2e85f9116b6505121f3c4395765494305caf01b612063bce17debfcacc30bc34f357f7fc9edf9a9836fba1ef8c5bad676eb937e81e74c313944fc4b8ef815b2d65258884dcf20104afad7cd25182763cb6979b64d5f17b011da4b27926289061590d8ace5b9a5d869ee42504a5e91348ac1ec5bd56c76dc7e71a3c83ae9c5db36e1bbff28aded4fd8439e81215d284e72b784fabd9e3a8db0d48da70532e97da2febbd32df02e3b48d08d088693263a23634a185c11dce0712594a3c00bd4ddb134a705639e06fa"
}

expires_inは、tokenが無効になるまでの秒数とのこと。
AuthServiceProviderクラスのboot()で指定可能。

AuthServiceProvider

        Passport::tokensExpireIn(now()->addDays(15));
        Passport::refreshTokensExpireIn(now()->addDays(30));

※ただし認証時に正しくチェックされないとの情報あり(未検証)

Get user information

次にユーザー情報を取得してみます。
ヘッダーのAuthorizationで、アクセストークンを渡します。

Method: Get
URL: youredomein.com/api/user
Header: [Accept => application/json,
Authorization => Bearer xxxxxxxxxxxxxxxxx]

Result:

{
"id": 1,
"name": "My Name",
"email": "my.name@mail.com",
"email_verified_at": null,
"created_at": "2018-00-00 00:00:00",
"updated_at": "2018-00-00 00:00:00"
}

Refresh token

Tokenのリフレッシュです。

Method: POST
URL: youredomein.com/oauth/token
Header: [Content-Type: application/json;]
body:

{
    "grant_type": "refresh_token",
    "refresh_token": "def50200c2111621e18b14a7a065ea75eeaa004fe07c25b20bb78e382f9b06843e7c3c9e41d5b23b3883f9ef646432a685734efc4022c88163512ef8242b289730763c6aaca2ab541eef807b2b704b440a76696f337e20a28bc8f3618045076ecf4335b5ba08a7361a4f467ebb917208848815af1e6717faaa0e330907754e3b823afea6657e4acfbf62cde5f4991bbc6fb40e1985f55d1bf665867e7db3aa087a1242654bea511008fcc1730525026ae0736c498ca96f656acde5757da0c9124559b29f68a6aa6914cdc33360826b0e07bdd9bcd09d963238e8c537b75afd17a27c28db5d51432453452d26c6c2f4d61276ed1176dff1fd3acb6a0462f6f0da1cb802442b32d615e7ec2a14b463a524bc51e6c33069ec879e72683f9c98931c36a14ece4dd74d4d44a4def2f7e2e208a8d47672dce019c66ef4847643d669b7c5796899f7465000ffbd998f196caf47095e00c3cb310c43784dc154e7ce1c51c54c3b43",
    "client_id": 2,
    "client_secret": "r5V5xoKmBrU2kOmG4ZOrF0iCcJ4lfVncTvWnRk2P",
    "scope": "*"
}

Result:

{
"token_type": "Bearer",
"expires_in": 1296000,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjAyNWNmZGE2ZDNjZjQ1NTUyMjc1YzI1ZjI4MWJkZWZiMmZhMTY1MmMyNThlMDdhYmY0NWE4ZDdiZTdjN2UxOWY0NDBiNWIyMGQ4NzJiMmQyIn0.eyJhdWQiOiI2IiwianRpIjoiMDI1Y2ZkYTZkM2NmNDU1NTIyNzVjMjVmMjgxYmRlZmIyZmExNjUyYzI1OGUwN2FiZjQ1YThkN2JlN2M3ZTE5ZjQ0MGI1YjIwZDg3MmIyZDIiLCJpYXQiOjE1MzgxMjY1OTUsIm5iZiI6MTUzODEyNjU5NSwiZXhwIjoxNTM5NDIyNTk1LCJzdWIiOiIxIiwic2NvcGVzIjpbIioiXX0.KxT_L3q8-kuq8Jhz6YjljWjJb90OObbpPJ_vYNkPRWR7Rho0kFvtiVgbjwKTfxFWYaFENpw3nDI8r1kCTn50UWRPz3NyeFCu8Q7BiXAigq-gsDJ5HpqQZs21JdvGkC7SNR00yGq7ij6rIsdDvnSN6g08zzacx0gpX3fMAQ60Wa3qrcc14SQWecG2zI7PrxVn_9vuxOMtChNMDJvg1vIytteOzdoE2RS_ITxYEpoTYlm4sB0Fjq6X81Llu7lT8oE8YQRHcUrf1CyyT_C-hQfbmC1r_ZcHK6H6vqzefEZ5O8lceY15J-klZXdbwlkCcSADpFkg_Ssu9cRlVEmHK19URgcb6DTLYWVgw0P9Mqbsr2QBCqaaUTHon1vsflZ9cq_cKqZ_lMYK9GsnwNn-GeZoB83WIGNVMbiY6t3rtWaf-HPkS0Y0WUe6FUA7FomKHkHyhXHQhqH_wDgU1lgazLWTn9zO87FWCZxWvkpgf3qQSS_QYPFeiJzmNb_s6StxKU77QqP6duhA9JSrBBzSVwxivRdXFCHmGMqG9meKfKE5_geLcP_NEhEydsCxvvNa5pfPW7FqpjgI4s1w8XWg1y6dK1Htjn5uBUdJY8ZhEOKuF8X-xq6GVuWJrUFsebAw5AQ1FGJI7_HxetJhNsVvsO4nP1nYSs4M44Wxgo1VR439vXM",
"refresh_token": "def50200c668fc733991b8cb84378b048f97a03fcee9bbf049ba18c8f468721f2e18c3c42e60bf9dd35c144114738393ce2552a9824da39f4f04bb7e778243339e71571468917689ee90bb7130a1e87f0cc52def018aca568578597a0521e2b061e5f6e62e3de8b97bfc93134459941125537a10337df917df9313faf3bc17fc038682068e8ed714d97390a9b18e34425134c1f250c724102579c55db637c0df0753bcf27c2fc2f94335cbd03827f78f5f1281cbf6d5f9ef5a2da01ec0c9737584741324582ec33ba1da4c0c1d31c3fc3eab8e7b9e21cf4c6b243259a73e5ed0e0ecef23738a1b9c639b94940750ee5526787a5e265e3e0daef589706c150264b0a1a6d2f67578b04018339b1689864ec4a4c9ee4c156669c97e4cae6f244b56b3fe516ae404315a07d97f0afd939899b5ea51d6038e8d83415572d849d5a7a944a861daa82b6f6a22e824fde67b6930498a20fb441961d07d190c0f9bb16bc964a5ef0f"
}