Laravel Passportとは
平たく言えばAPIにOAuthに従った認証機能を追加できる機能。Laravelのエコシステムの1つ。
すこし大げさなので標準のapi_tokenを利用したり、外部ライブラリを利用するのもあり。
対応するToken発行方式
PassportはOAuthで定義されている4つの方法に加え、Personal Access (Grant) Tokenという主に内部利用向けのToken発行ができる(名前はOAuthの正式な呼び方とは微妙に違うみたい)。
- OAuth2 with authorization codes (Auth Code)→SNS認証でよく使うやつ(確認画面あり・Code発行あり)
- Password Grant Token(確認画面無し。Codeなし。ID, PWでTokenを発行)
- Implicit Grant Token(いきなりTokenを発行。安全性に問題?)
- Client Credentials Grant Token(マシン間通信向け。個人の認証無し)
- Personal Access Token(その名の通り、個人・内部利用向け)
私氏自身、OAuth勉強中の身なので間違いなどあればご指摘を。
個人的な利用頻度順に試してみる
一般的にAuth CodeはSNS認証でよく使いますが、自分がプロバイダ側になることはあまりない。
個人的には信頼関係のある人間(社内含む)にTokenを発行してAPIを使ってもらうというシーンを想定するので以下の順序で機能を試してみる。
- Personal Access Token
- Password Grant Token(jwt-authはこれに対応?)
- Client Credentials Grant Token
- Auth Code
- Implicit Grant Token
環境準備
Laravelのインストールと.envの設定
Passportを利用したい人が詰まることはないと思うので割愛します。
Passportのインストール
composerでインストール。
composer require laravel/passport
認証機能のスキャフォールド
必須ではありませんが、ユーザーの登録に利用したり、不要なエラーを防止できるので追加しておきます。
php artisan make:auth
Migrate
migrateの実行。
php artisan migrate
oauth_*から始まるテーブルがいくつか作成されます。
app/User.phpの編集
利用するモデルをいじります。
コメントは削除しています。
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
+use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use Notifiable;
+ use HasApiTokens;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
}
app/Providers/AuthServiceProvider.phpの編集
Passportで利用するルートを登録します。
コメントは削除しています。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
+use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
+ Passport::routes();
}
}
config/auth.phpの編集
api guardのdriverをpassportに変更します。なお、先程User.phpをいじったのは、ここでproviderがusersになっているからです。
必要に応じて他のテーブルを利用することもできます。
コメントは削除しています。
<?php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
+ 'driver' => 'passport',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
];
Keyの発行
暗号化に利用するシード値などを生成します。
php artisan passport:installとすると、keysも実行されるのですが、ここでは個別に実行します。
php artisan passport:keys
テストユーザーの生成
テストで利用するユーザーを生成しておきます。ここでは2名のテストユーザーを作成しています。
- user1, user1@test.com, testtest
- user2, user2@test.com, testtest
ここではtinkerで作成しますが、make:authで生成された画面(register)から登録してもOKです。
php artisan tinker
Psy Shell v0.9.8 (PHP 7.2.8 — cli) by Justin Hileman
>>>
>>>
>>> $user1 = new App\User;
=> App\User {#2950}
>>> $user1->name = 'user1';
=> "user1"
>>> $user1->email = 'user1@test.com';
=> "user1@test.com"
>>> $user1->password = Hash::make('testtest');
=> "$2y$10$EfPa4c.4pNNbvsq1qiCbUea7ZhWKcuCWG483RQYYX2QEkef5iEduy"
>>> $user1->save();
=> true
>>>
>>> $user2 = new App\User;
=> App\User {#2958}
>>> $user2->name = 'user2';
=> "user2"
>>> $user2->email = 'user2@test.com';
=> "user2@test.com"
>>> $user2->password = Hash::make('testtest');
=> "$2y$10$XOpROv3mvrPYgS5erPjzW.tuhHtJk4BG1Tw6S.NxfkUgFo2u6PH76"
>>> $user2->save();
=> true
準備はとりあえず以上となります。
Personal Access Token
まず、Personal Access Tokenから試してみます。
商用環境での利用頻度は低いかもしれませんが、開発用等で利用することが想定されるため、Personal Access Tokenを試しておきましょう。
なお、Personal Access Tokenはexpire等を設定しても無視され、半永久的だそうです。ただ、頑張れば設定を変更することもできるようです。
クライアントの生成
OAuthでは、まずクライアント(ID)を生成(取得)する必要があるので実行します。
php artisan passport:client --personal
What should we name the personal access client? [Laravel Personal Access Client]:
> personal1
Personal access client created successfully.
Client ID: 1
Client Secret: jl46yLKUHxE5J3L4ypjhT60YWCG6pOkNl0BPdz5b
Tokenリクエスト
Tokenの取得は/oauth/tokenにアクセスすればよいのですが、Personal Access Tokenの場合、取得するユーザーでログインしている必要があります。ただ画面を用意するのが面倒なので、ここではLaravelのコード内で生成してみます。
LaravelのオフィシャルサイトではVue経由での取得が紹介されています。
とりあえずルート(api.php)に書きを追加します。
Route::get('/personal', function(){
$user = App\User::find(1);
$token = $user->createToken('token_for_user1')->accessToken;
return response()->json(['token' => $token]);
});
特定のuserを取得して、userからcreateToken()を実行しています(トレイトの追加で拡張されている)。
Tokenレスポンス
http://localhost:8000/api/personal にアクセスしてみます。と、以下のコードが生成されます。
別にjson形式にする必要はないです。
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjM5ZmVhZThjMTUyOGI1MGM3YjI2ZjEzN2Q4MWU1ZGFjMWJlOWFkZjBkYjBjMDg3ZWY2Njk5YmY5MjRlNjE0ZjZlOWJhZGZiOGUyMzMyNmM4In0.eyJhdWQiOiIxIiwianRpIjoiMzlmZWFlOGMxNTI4YjUwYzdiMjZmMTM3ZDgxZTVkYWMxYmU5YWRmMGRiMGMwODdlZjY2OTliZjkyNGU2MTRmNmU5YmFkZmI4ZTIzMzI2YzgiLCJpYXQiOjE1Mzg4MjQ1MzEsIm5iZiI6MTUzODgyNDUzMSwiZXhwIjoxNTcwMzYwNTMxLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.5vK0YJWvM_LZjFsHaUWdc9V0Xms0YEr1lxUotaL_A_B5LWK9HI9pJWydgGk_OfWwxGz8qj57nQGUKiVlmzvj2TfcK-qeUyb04G0cLlLNK_ncyML6pKQRd7t_Y2KSnW-N0xQh_18zOnO9DXP0CPapaKVLiR4tsPlkzG3i3sTQzXarJranW-aSsR5z56obAvSaMQ85lkS1mlbxkdeGpK8CxCJ6ikikqNk2w-x96_AcDt2wo8xFNTOc8I8DLb_geeK6_2KcibQ7WKZOSZnIQj1oeQKginhJUQJ_mozxuPUT4jOW_VZWfzSRdan8TV5DrfoCWaTN00ES1Ebf3O96HigM5aJMo6_PiWinbXwheQXmeCdB949LZpmTEhkWsEytvuDoMAOUCInMtSkr-YQRaKdVKAZzqqiDxH90lLWBjwQjx1Du2KsAhIE3FFcPFC1Eo279jnC8x_MuLodYicmo7FRVvZmyni1T6_6Dg3L-PFFIWR1lhX261gwHEUPzDDJ1eBRh1IPVkTT7_50OveUD2YZwCo5QC7KnlxrahEdKcskB6j7FgjarT-EMY03Osn7LWZKPqLEuoR0PUknHXHG7IVs0j_cjgaKV8vgK05LLo8Lyz1VjWX65U2BUXKJnOCzI90smJXSk5SihJ2TMftRpZ3eKECN4gJXD9oUXi-1axE6bxEI"}
APIリクエスト
取得したTokenを利用して認証付きのAPIにリクエストしてみます。
標準で/api/user という認証済みユーザーの情報を取得するAPIがあるのでそれをコールしてみます。
認証を通すためにはAuthorization: Bearer {token}をヘッダに添付して送ります。
なお、LaravelにAPIからのリクエストであることを認識させるためAccept: application/jsonも添付しています。
curl -H 'Accept: application/json' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjM5ZmVhZThjMTUyOGI1MGM3YjI2ZjEzN2Q4MWU1ZGFjMWJlOWFkZjBkYjBjMDg3ZWY2Njk5YmY5MjRlNjE0ZjZlOWJhZGZiOGUyMzMyNmM4In0.eyJhdWQiOiIxIiwianRpIjoiMzlmZWFlOGMxNTI4YjUwYzdiMjZmMTM3ZDgxZTVkYWMxYmU5YWRmMGRiMGMwODdlZjY2OTliZjkyNGU2MTRmNmU5YmFkZmI4ZTIzMzI2YzgiLCJpYXQiOjE1Mzg4MjQ1MzEsIm5iZiI6MTUzODgyNDUzMSwiZXhwIjoxNTcwMzYwNTMxLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.5vK0YJWvM_LZjFsHaUWdc9V0Xms0YEr1lxUotaL_A_B5LWK9HI9pJWydgGk_OfWwxGz8qj57nQGUKiVlmzvj2TfcK-qeUyb04G0cLlLNK_ncyML6pKQRd7t_Y2KSnW-N0xQh_18zOnO9DXP0CPapaKVLiR4tsPlkzG3i3sTQzXarJranW-aSsR5z56obAvSaMQ85lkS1mlbxkdeGpK8CxCJ6ikikqNk2w-x96_AcDt2wo8xFNTOc8I8DLb_geeK6_2KcibQ7WKZOSZnIQj1oeQKginhJUQJ_mozxuPUT4jOW_VZWfzSRdan8TV5DrfoCWaTN00ES1Ebf3O96HigM5aJMo6_PiWinbXwheQXmeCdB949LZpmTEhkWsEytvuDoMAOUCInMtSkr-YQRaKdVKAZzqqiDxH90lLWBjwQjx1Du2KsAhIE3FFcPFC1Eo279jnC8x_MuLodYicmo7FRVvZmyni1T6_6Dg3L-PFFIWR1lhX261gwHEUPzDDJ1eBRh1IPVkTT7_50OveUD2YZwCo5QC7KnlxrahEdKcskB6j7FgjarT-EMY03Osn7LWZKPqLEuoR0PUknHXHG7IVs0j_cjgaKV8vgK05LLo8Lyz1VjWX65U2BUXKJnOCzI90smJXSk5SihJ2TMftRpZ3eKECN4gJXD9oUXi-1axE6bxEI' http://localhost:8000/api/user
リクエストにはcurlとかよりPostmanとかを使うほうが可読性、操作性が良いかもしません。
APIレスポンス
無事取得できたようです。
{"id":1,"name":"user1","email":"user1@test.com","email_verified_at":null,"created_at":"2018-10-06 11:10:52","updated_at":"2018-10-06 11:10:52"}
エラーの確認
少しTokenを編集してリクエストすると認証エラーになりました。
{"message":"Unauthenticated."}
このメッセージはapp/Exceptions/Handle.phpでunauthenticated()をオーバーライドすると変更できます。
Password Grant Token
登録済みのIDとPasswordを送信し、認証後Tokenが発行される形式です。
自社やパートナー企業との連携等が利用シナリオでしょうか。
クライアントの生成
--passwordオプションをつけてクライアントを生成します。
php artisan passport:client --password
What should we name the password grant client? [Laravel Password Grant Client]:
> password1
Password grant client created successfully.
Client ID: 2
Client Secret: GVzzSWmP5nsmbOMQGvHnvAoJqXHaNeDPC6SH3I53
Tokenリクエスト
Tokenをリクエストしてみます。リクエスト先は/oauth/tokenになります(token要求は常にこのURIが利用されます)。
json形式で送るにはContent-Type: application/jsonが必要です。
curl -X POST -H 'Content-Type: application/json' -d '{"grant_type":"password", "client_id":"2", "client_secret":"GVzzSWmP5nsmbOMQGvHnvAoJqXHaNeDPC6SH3I53", "username":"user1@test.com", "password":"testtest","scope":"*"}' http://localhost:8000/oauth/token
なお、以下のPOSTパラメーを送っています。
{
"grant_type":"password",
"client_id":"2",
"client_secret":"GVzzSWmP5nsmbOMQGvHnvAoJqXHaNeDPC6SH3I53",
"username":"user1@test.com",
"password":"testtest",
"scope":"*"
}
Tokenレスポンス
レスポンスです。tokenはもちろん、refresh_tokenも返ります。有効期限は標準では1年のようです。
{"token_type":"Bearer","expires_in":31536000,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijc3OTFmN2JkMzM5MjEyZDBiYmZmMmE3M2RmN2YzNGNlYWU2YzY0ZThhOTBiZTdhYTViOWU4YmZkZTU3MmI3YzNlNzhjMzRhOGQ4YTAwZDA4In0.eyJhdWQiOiIyIiwianRpIjoiNzc5MWY3YmQzMzkyMTJkMGJiZmYyYTczZGY3ZjM0Y2VhZTZjNjRlOGE5MGJlN2FhNWI5ZThiZmRlNTcyYjdjM2U3OGMzNGE4ZDhhMDBkMDgiLCJpYXQiOjE1Mzg4MjYxODAsIm5iZiI6MTUzODgyNjE4MCwiZXhwIjoxNTcwMzYyMTgwLCJzdWIiOiIxIiwic2NvcGVzIjpbIioiXX0.4Pp-FB42ITy-GcNuhKJKY2GSBrbw7G2uniDssK0GwIXrY-C3gQexAhiw1eWzy5FOehR8Ygov2-dJMKxb7Ej0fSQMjUweX4SQAp3yYmuB7Vc9eAR4z7xoxoJoTSd854I-kTjqwg5W3-EC1iIM2wINI5iEgBWtobu2pGWQw7bIObYr583FWmj0Khx0l8knEXK-7n_oJY7eramrm9hX1KOigeVD1wisjTQKXCAEAMh54ChMh5AWc-4bA5qIiVc-MSgkjTKThLsklwyB8Y9Cj-69PoSMf2bE0YFgH7ODdjEogMWylIDvr79PACXKtevoSg63ANMKWxyIIq6XGnOqwHGqf-w-ModeRkFRb7LlHNF0CED2sEmDTEeTQjKodfzsuc2eN1zXEtDuhLXp0UGgBy2o5h93LNEnzxbsQ4vb8CaN_-tajBg8nkUh8XkAZyH6U9VvEFSoJ8NmqT8OzCZBvBxlxYhrzinh8H7X1UcBd0sM0n8jOPRHziqlQjYoLiVX2uf_zoPJF0UjU-4_lIiOzsAT19obObb8zZZElf2Yp1ySIf336MHalrzIrv3jEA6FHLb1T3db3Tx_hQGUVpUTnAsnbml-N0-m0ZrL9_Ncko62aWRB0ImbAAJr3JWWwHFG54JyG-1hevczRPA3c3_H6EMARyEDkWG2yH0hTNkvhbRgcS8","refresh_token":"def50200f03c31e644726560d410cf9e016a895b358b18101ed0e00f3d46b76148bb3bcd97d4f6dec1f3d6c79269dc70b09a02713509800222703dbd42375795710812fc9222fcb355450d67d399627a462ea5a52dc75b8cc962e455111ad3709f99f040d9425ad0e800ccafc98c672af8a4ae9717b4e4880e8b8ca68799605c0197a624861516c49b6e49aecfddfdca400f5e5d8500d193b6ee36f14a42c9c004c52d87a70160815927173ebb898b521d3309e8fc6bf8b38cb6e96ec0798a16c692f8e6be45924631cd51708ce1f0f8a6710001cb1cb5385d8f0b3ed02ca60f1cf1ea2031f89947571cd51ba4d4a60973169f86b8d6c2c9a8e814412d331d81d05424f45879ff926dda4ef9af60432ae21418e118aa6dd26aab7f3deabf52fe959cf9ee0df66a0fff8e73ec7f7f3089d1dbd9da5e675d15c576b56135e74c36f0492c3a52664371966ca4c1d01643dc115a67424054862f59ecf927bef5465c50f96fd3"}
APIリクエスト
受け取ったtokenを利用してAPIにリクエストしてみます。
curl -H 'Accept: application/json' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijc3OTFmN2JkMzM5MjEyZDBiYmZmMmE3M2RmN2YzNGNlYWU2YzY0ZThhOTBiZTdhYTViOWU4YmZkZTU3MmI3YzNlNzhjMzRhOGQ4YTAwZDA4In0.eyJhdWQiOiIyIiwianRpIjoiNzc5MWY3YmQzMzkyMTJkMGJiZmYyYTczZGY3ZjM0Y2VhZTZjNjRlOGE5MGJlN2FhNWI5ZThiZmRlNTcyYjdjM2U3OGMzNGE4ZDhhMDBkMDgiLCJpYXQiOjE1Mzg4MjYxODAsIm5iZiI6MTUzODgyNjE4MCwiZXhwIjoxNTcwMzYyMTgwLCJzdWIiOiIxIiwic2NvcGVzIjpbIioiXX0.4Pp-FB42ITy-GcNuhKJKY2GSBrbw7G2uniDssK0GwIXrY-C3gQexAhiw1eWzy5FOehR8Ygov2-dJMKxb7Ej0fSQMjUweX4SQAp3yYmuB7Vc9eAR4z7xoxoJoTSd854I-kTjqwg5W3-EC1iIM2wINI5iEgBWtobu2pGWQw7bIObYr583FWmj0Khx0l8knEXK-7n_oJY7eramrm9hX1KOigeVD1wisjTQKXCAEAMh54ChMh5AWc-4bA5qIiVc-MSgkjTKThLsklwyB8Y9Cj-69PoSMf2bE0YFgH7ODdjEogMWylIDvr79PACXKtevoSg63ANMKWxyIIq6XGnOqwHGqf-w-ModeRkFRb7LlHNF0CED2sEmDTEeTQjKodfzsuc2eN1zXEtDuhLXp0UGgBy2o5h93LNEnzxbsQ4vb8CaN_-tajBg8nkUh8XkAZyH6U9VvEFSoJ8NmqT8OzCZBvBxlxYhrzinh8H7X1UcBd0sM0n8jOPRHziqlQjYoLiVX2uf_zoPJF0UjU-4_lIiOzsAT19obObb8zZZElf2Yp1ySIf336MHalrzIrv3jEA6FHLb1T3db3Tx_hQGUVpUTnAsnbml-N0-m0ZrL9_Ncko62aWRB0ImbAAJr3JWWwHFG54JyG-1hevczRPA3c3_H6EMARyEDkWG2yH0hTNkvhbRgcS8' http://localhost:8000/api/user
APIレスポンス
認証後、ユーザー(自分自身)のデータが取得できています。
{"id":1,"name":"user1","email":"user1@test.com","email_verified_at":null,"created_at":"2018-10-06 11:10:52","updated_at":"2018-10-06 11:10:52"}
Tokenリフレッシュリクエスト
せっかくなのでtokenのリフレッシュも行ってみます。
curl -X POST -H 'Content-Type: application/json' -d '{"grant_type":"refresh_token", "client_id":"2", "client_secret":"GVzzSWmP5nsmbOMQGvHnvAoJqXHaNeDPC6SH3I53", "scope":"*", "refresh_token":"def50200f03c31e644726560d410cf9e016a895b358b18101ed0e00f3d46b76148bb3bcd97d4f6dec1f3d6c79269dc70b09a02713509800222703dbd42375795710812fc9222fcb355450d67d399627a462ea5a52dc75b8cc962e455111ad3709f99f040d9425ad0e800ccafc98c672af8a4ae9717b4e4880e8b8ca68799605c0197a624861516c49b6e49aecfddfdca400f5e5d8500d193b6ee36f14a42c9c004c52d87a70160815927173ebb898b521d3309e8fc6bf8b38cb6e96ec0798a16c692f8e6be45924631cd51708ce1f0f8a6710001cb1cb5385d8f0b3ed02ca60f1cf1ea2031f89947571cd51ba4d4a60973169f86b8d6c2c9a8e814412d331d81d05424f45879ff926dda4ef9af60432ae21418e118aa6dd26aab7f3deabf52fe959cf9ee0df66a0fff8e73ec7f7f3089d1dbd9da5e675d15c576b56135e74c36f0492c3a52664371966ca4c1d01643dc115a67424054862f59ecf927bef5465c50f96fd3"}' http://localhost:8000/oauth/token
送信パラメータは以下の通り。
{
"grant_type":"refresh_token",
"client_id":"2",
"client_secret":"GVzzSWmP5nsmbOMQGvHnvAoJqXHaNeDPC6SH3I53",
"scope":"*",
"refresh_token":"refresh_token..."
}
Tokenリフレッシュレスポンス
再度、tokenとrefresh_tokenが発行されます。
なお、refresh_tokenを発行すると、前のtokenは利用できなくなりますので注意が必要です。
{"token_type":"Bearer","expires_in":31536000,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjVmM2JiZDJjNzU4MTkwNDcyOGI3YzMzMTg2NjQ1NTQ0MjQ2ZjZmYmY1ZWY0M2EwYjJhY2NjODBmZjkzY2Q5MDFjNjY1ZjhiNTJhMDVjZDUzIn0.eyJhdWQiOiIyIiwianRpIjoiNWYzYmJkMmM3NTgxOTA0NzI4YjdjMzMxODY2NDU1NDQyNDZmNmZiZjVlZjQzYTBiMmFjY2M4MGZmOTNjZDkwMWM2NjVmOGI1MmEwNWNkNTMiLCJpYXQiOjE1Mzg4MjY1NTksIm5iZiI6MTUzODgyNjU1OSwiZXhwIjoxNTcwMzYyNTU5LCJzdWIiOiIxIiwic2NvcGVzIjpbIioiXX0.atpqFPqfGMFE2wEcftkQTFdzycwRl0jXcaEyB-WIk2fXMM7r7-wML83YerZ4HnaXHS36Ee1V2ibNJcr3UpyCGQkRVWNahryHFWv0KWrGZX36uuCd1T43WlvrmEsEz5rQVPYMHE6uht1IsgRlpTcPyI7OtvECVOP6XKf5YRB4huH-2T-rI7BkcP0e8WFleNVsLPLRh16l_znAhVABAt_WgWdr6-5ldo3daGXP5wow_t2WskRBXqI5jfVtfqe_nqfR4HVK6MGYU0mPlwSufXBVAoM3ldr8S4Wyln7APRenTcTet4RcfdhjVoZHV_--tJCXr83JN5gcZ1dD7mLaFrgc5A7vRzyFjmCyE-yxDsV90WcYh5EIBK8kmKqvHPkvtbBdW_G0vQzhuyC-SLnph1xlwI2nDuvyb90ofOCQ47S4eyV8xvGm4FDNpscJy00wX5fzQEPQBLQqmq4jZ1bP6swXxLwpO-7BZRj_B5rHs2-klUubQAQvapKF6q0M3MMYQgHda1a8ebF83TSSXZV-ywLM3OWxiXjO2pcBNg6Y3-IwhZX5RUS8R6efvA-g-_Y2rVtbSISCkYb3dP6REX-rtBbfLn1K6h1h122rPKxbwkkVhWQbcRtpex_09TjzBjw1fHkjPIJVACOITN-dFUv2rrQPpQbDW7xLxGYYPVUAcvyE42Q","refresh_token":"def50200921c2a9639d11068423148f7663db2efe53d3e052098ec812b800033c516aecd67d702326019e4a944d83ab8f909d0ea3a034e063c247f99cc3d1321d657ae6c63c869e7227fd99f1c480c93e48e8e95277b95c7c4e0ea60e3ccadce5fad4e70422357e44840e1dc0998c2ec104223f78dfb6e79d3fe095bac2e703d93d87133a1a625ce4d2c5e336ef75b02587bbab5c2711dd31e2cb332c8dd9674b88b3c626cac7de54b9742acffb8402e586f494e56db3bd766c9b0c9147a15fea2c39be48aa88c80c5e6aab2d5db73f12ac9bcbc8d669d77303eeddfe28c355061dd32bd9e531836262a2abc1472fe13b87aca53c77cfe79da45795f8f0cf38f79a5dba635d6b14f82fb3a3ac8400f86c0815545cc34af5ad605928255fc1670a1e88701e81652556bee97408e465198903083c756db9ba9358dc1c26ffefd2039fcaab6f0bee20a0d1a6d1abea070491b1927d31e675cdc6a7580da578128ea6d803125"}
Client Credentials Grant Token
マシン間の通信に適していると書いてありますね。バッチ処理でAPI連携する場合などでしょうか。
クライアントの生成
専用のクライアント生成コマンドは無いようです。
ここでは上記のPassword Grant Tokenで生成したクライアント(client_id = 2)を利用してみます。
これでいいのかが正直謎。
ミドルウエアの追加
Client Credentials Grant Tokenを利用するにはミドルウエアの追加が必要なようです。
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
+use Laravel\Passport\Http\Middleware\CheckClientCredentials;
class Kernel extends HttpKernel
{
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
+ 'client' => CheckClientCredentials::class,
];
}
ルート(ミドルウエア付き)の設定
ミドルウエアが適用されたルートを用意してみます。
なお、Client Credentials Grant Tokenでは、個人の特定はできない(ユーザー認証はしない)のでログイン状態を前提としたデータの取得はできないようです。
それを検証するために2つのルートを用意しました。
1つは、今まで通り、/api/userと同じ機能(client1)。もう1つは個人情報は取得しないが、認証?は必要なページ(client2)。
なお、auth:apiと併用はできないようです(認証エラーとなる)。
Route::middleware('client')->get('/client1', function (Request $request) {
return $request->user();
});
Route::middleware('client')->get('/client2', function (Request $request) {
return response('auth contents');
});
Tokenリクエスト
では、まずTokenをリクエストしてみます。
curl -X POST -H 'Content-Type: application/json' -d '{"grant_type":"client_credentials", "client_id":"2", "client_secret":"GVzzSWmP5nsmbOMQGvHnvAoJqXHaNeDPC6SH3I53", "scope":"*"}' http://localhost:8000/oauth/token
送信パラメータは以下の通り。
{
"grant_type":"client_credentials",
"client_id":"2",
"client_secret":"GVzzSWmP5nsmbOMQGvHnvAoJqXHaNeDPC6SH3I53",
"scope":"*"
}
Tokenレスポンス
access_tokenは返りますが、refresh_tokenはありません。
{"token_type":"Bearer","expires_in":31536000,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImUxYTBmMDg4YzE5NTRlMjJkYjNkNDA0NzUzYjM1OGI4NWQwMTRmNjNhYTQ2OTBjZDNjNzlmYTQxNTVlMDYzYWRkNGFiZWVmNjAwNmEyNzdlIn0.eyJhdWQiOiIyIiwianRpIjoiZTFhMGYwODhjMTk1NGUyMmRiM2Q0MDQ3NTNiMzU4Yjg1ZDAxNGY2M2FhNDY5MGNkM2M3OWZhNDE1NWUwNjNhZGQ0YWJlZWY2MDA2YTI3N2UiLCJpYXQiOjE1Mzg4Mjc2MjcsIm5iZiI6MTUzODgyNzYyNywiZXhwIjoxNTcwMzYzNjI3LCJzdWIiOiIiLCJzY29wZXMiOltdfQ.ennDYPoktYtZMpbvg80wyxt71vaX1ziBHOgPv3d0i8XoOVjeNGzWi9s2GcZ7Bhk99owBDLGzl1z-EOM5ihcUT1aRmjmOAJTOptQW5rGV000cetGKDGNig8xJwTEMvaVCzNWEZqi0bDxWG-PBDzR7MQjNtPvDxc6nP3pmUhJby2V7PLJVO6_ZYPRXPwOclOV9E6YNWpG9s77n44p2XPChGnG2fh7l5sjqLu66zshvmxRf9vF_5AkDoopWFNMQiPqGsWhJlc5KjU_Wuzdamr9uyaI4Hv-WpdG5aV8dc2pzaLK1Z5UvxXdD3LvQAvvqk4MY14zveUW_e-92VFMuSpFQ-bJs22LCo2-axDfLbW21e7seVIOqrZx5pquKcbja3iW8ca6_P0KTWATXZBsFRJo6DFe2gI4eNkYQyBAlf96KVxUgEDD5ADr1UzDqJ792eVrTkPyELkbPGRKxEeziTpJgXxBypRyDCySXLpOSQmMpyP430cvivcsFj5pwaF0xGlOZSHBWa9d1W5FriWzMBsmnAvwllDmD_EWvDh7wK_ccAthb7eNjGk67Ag7eWDctmNuI02Xh2OwhsRp9foUAbxrNOpnZQEjvouw-MmdpmpvYAGijg6keMZiwyMtvIDqqqG12y4_8n5NcslpdhKn1oC8D96h804ae-kRCGOieDEf4sP8"}
APIリクエスト1
まず、/api/client1にリクエストしてみます。
curl -H 'Accept: application/json' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImUxYTBmMDg4YzE5NTRlMjJkYjNkNDA0NzUzYjM1OGI4NWQwMTRmNjNhYTQ2OTBjZDNjNzlmYTQxNTVlMDYzYWRkNGFiZWVmNjAwNmEyNzdlIn0.eyJhdWQiOiIyIiwianRpIjoiZTFhMGYwODhjMTk1NGUyMmRiM2Q0MDQ3NTNiMzU4Yjg1ZDAxNGY2M2FhNDY5MGNkM2M3OWZhNDE1NWUwNjNhZGQ0YWJlZWY2MDA2YTI3N2UiLCJpYXQiOjE1Mzg4Mjc2MjcsIm5iZiI6MTUzODgyNzYyNywiZXhwIjoxNTcwMzYzNjI3LCJzdWIiOiIiLCJzY29wZXMiOltdfQ.ennDYPoktYtZMpbvg80wyxt71vaX1ziBHOgPv3d0i8XoOVjeNGzWi9s2GcZ7Bhk99owBDLGzl1z-EOM5ihcUT1aRmjmOAJTOptQW5rGV000cetGKDGNig8xJwTEMvaVCzNWEZqi0bDxWG-PBDzR7MQjNtPvDxc6nP3pmUhJby2V7PLJVO6_ZYPRXPwOclOV9E6YNWpG9s77n44p2XPChGnG2fh7l5sjqLu66zshvmxRf9vF_5AkDoopWFNMQiPqGsWhJlc5KjU_Wuzdamr9uyaI4Hv-WpdG5aV8dc2pzaLK1Z5UvxXdD3LvQAvvqk4MY14zveUW_e-92VFMuSpFQ-bJs22LCo2-axDfLbW21e7seVIOqrZx5pquKcbja3iW8ca6_P0KTWATXZBsFRJo6DFe2gI4eNkYQyBAlf96KVxUgEDD5ADr1UzDqJ792eVrTkPyELkbPGRKxEeziTpJgXxBypRyDCySXLpOSQmMpyP430cvivcsFj5pwaF0xGlOZSHBWa9d1W5FriWzMBsmnAvwllDmD_EWvDh7wK_ccAthb7eNjGk67Ag7eWDctmNuI02Xh2OwhsRp9foUAbxrNOpnZQEjvouw-MmdpmpvYAGijg6keMZiwyMtvIDqqqG12y4_8n5NcslpdhKn1oC8D96h804ae-kRCGOieDEf4sP8' http://localhost:8000/api/client1
APIレスポンス1
該当するユーザーがいないため何も戻りません(が、認証エラーがでるわけでもありません)。
(何も返らない)
APIリクエスト2
次に、/api/client2にリクエストを投げてみます。
curl -H 'Accept: application/json' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImUxYTBmMDg4YzE5NTRlMjJkYjNkNDA0NzUzYjM1OGI4NWQwMTRmNjNhYTQ2OTBjZDNjNzlmYTQxNTVlMDYzYWRkNGFiZWVmNjAwNmEyNzdlIn0.eyJhdWQiOiIyIiwianRpIjoiZTFhMGYwODhjMTk1NGUyMmRiM2Q0MDQ3NTNiMzU4Yjg1ZDAxNGY2M2FhNDY5MGNkM2M3OWZhNDE1NWUwNjNhZGQ0YWJlZWY2MDA2YTI3N2UiLCJpYXQiOjE1Mzg4Mjc2MjcsIm5iZiI6MTUzODgyNzYyNywiZXhwIjoxNTcwMzYzNjI3LCJzdWIiOiIiLCJzY29wZXMiOltdfQ.ennDYPoktYtZMpbvg80wyxt71vaX1ziBHOgPv3d0i8XoOVjeNGzWi9s2GcZ7Bhk99owBDLGzl1z-EOM5ihcUT1aRmjmOAJTOptQW5rGV000cetGKDGNig8xJwTEMvaVCzNWEZqi0bDxWG-PBDzR7MQjNtPvDxc6nP3pmUhJby2V7PLJVO6_ZYPRXPwOclOV9E6YNWpG9s77n44p2XPChGnG2fh7l5sjqLu66zshvmxRf9vF_5AkDoopWFNMQiPqGsWhJlc5KjU_Wuzdamr9uyaI4Hv-WpdG5aV8dc2pzaLK1Z5UvxXdD3LvQAvvqk4MY14zveUW_e-92VFMuSpFQ-bJs22LCo2-axDfLbW21e7seVIOqrZx5pquKcbja3iW8ca6_P0KTWATXZBsFRJo6DFe2gI4eNkYQyBAlf96KVxUgEDD5ADr1UzDqJ792eVrTkPyELkbPGRKxEeziTpJgXxBypRyDCySXLpOSQmMpyP430cvivcsFj5pwaF0xGlOZSHBWa9d1W5FriWzMBsmnAvwllDmD_EWvDh7wK_ccAthb7eNjGk67Ag7eWDctmNuI02Xh2OwhsRp9foUAbxrNOpnZQEjvouw-MmdpmpvYAGijg6keMZiwyMtvIDqqqG12y4_8n5NcslpdhKn1oC8D96h804ae-kRCGOieDEf4sP8' http://localhost:8000/api/client2
APIレスポンス2
ミドルウエアを通過して、コンテンツが表示されます。
auth contents
Auth Code
SNS認証では一番よく見るパターンです。
クライアントの生成
まずはクライアント生成。どのuser IDに割り当てるか聞いてきます。
php artisan passport:client
Which user ID should the client be assigned to?:
> 1
What should we name the client?:
> auth_code1
Where should we redirect the request after authorization? [http://localhost/auth/callback]:
> http://localhost/callback.php
New client created successfully.
Client ID: 3
Client secret: qhP34Alx3MGAgEteQ8VzXnk977wWvuOceNKZ6pS6
[xxxでログイン」に相当するコンテンツの作成(通常は外部サービス)
この機能は通常、(Laraveで作ったサービスと)連携する外部サービスが起点になります。
[xxxxでログイン」という感じのやつです。個々ではそのボタンがクリックされた際を想定した動きを検証します。
必要コンポーネント(Guzzle)のインストール
テストするのにGuzzle使うのでインストールします。
composer require guzzlehttp/guzzle
下記が[xxxxでログイン]ボタンを押したときの動作です。
[facebookでログイン」とかのイメージ。
簡易コード
いきなりリダイレクトするだけ。本来はJSとかでボタンクリックイベントとかで実行することになるでしょう。
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client as Client;
$guzzle = new Client;
$query = http_build_query([
'client_id' => '3',
'redirect_uri' => 'http://localhost/callback.php',
'response_type' => 'code',
'scope' => '',
]);
header('Location: http://localhost:8000/oauth/authorize?'.$query);
確認画面(プロバイダ側:Laravel自動生成)
Laravelが用意する標準の画面が出ます。
この画面を出すためには先にcallbackを用意しておかないとエラーが出るかも。
Callback先
Authorizeボタンをクリックすると、指定したcallback先に転送され、最終的にaccess_tokenが表示されます。
よく見ると、一度codeを受け取り、さらにそのcodeを利用してaccess_tokenをリクエストしているのがわかります。これがAuth Codeと呼ばれる所以です。
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client as Client;
$http = new Client;
if($_GET['code']){
$response = $http->post('http://localhost:8000/oauth/token',[
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => '3',
'client_secret' => 'qhP34Alx3MGAgEteQ8VzXnk977wWvuOceNKZ6pS6',
'redirect_uri' => 'http://localhost/callback.php',
'code' => $_GET['code'],
],
]);
$res = json_decode((string)$response->getBody(), true);
// var_dump($res);
echo $res['access_token'];
}
下記のようなtoken表示されます。
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjJlNWYzOTExMTcyZmM5MTkxOTZhZTI1MGNmY2ZkOGNhNTExNzFmN2I1Y2E5M2I0OGE0ODFiNDQzOTlhNDAxNTBmNjM4OWJhNjFjMDBlYTY5In0.eyJhdWQiOiIzIiwianRpIjoiMmU1ZjM5MTExNzJmYzkxOTE5NmFlMjUwY2ZjZmQ4Y2E1MTE3MWY3YjVjYTkzYjQ4YTQ4MWI0NDM5OWE0MDE1MGY2Mzg5YmE2MWMwMGVhNjkiLCJpYXQiOjE1Mzg4Mjg4ODAsIm5iZiI6MTUzODgyODg4MCwiZXhwIjoxNTcwMzY0ODgwLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.ROGkKk_BRTCuW2pUrq7PegzNnrF1Bo3a6Q0-v3T_9s3AJ33ZtZWyuD6QSxVJpPFWxiRttkno-5kFiNk0Ne8okg3XUwA1WQqJwZMlXjn1A2LmYO2NZ-KihgfjXKkncYwxPi3VsE84chIPRfOFokpy5vcVMtV7ds7jkl3zThTks5AqTPDNwCvMK95cYuFmtUfY8f__FRlLvEU2qaTbHVt7UJbe-l_P1LZEhfkZDQcPDkddkGn0W_5Zwgk5VqEEJezv1W07Yrq7BiWGzqO227XWgbwwZT4S6BX2l9Yka8aQGdqUkW-zj3Eeq07gLyRTDdzRd2tICZGn6_sXoChXeT_uu6_f3sWSiS8nn1StMW_4zEfBW2lbb8H1VQzS4Y5SMUqwCnSvZ2OV1-nG_e0KPd9HJeCz9q5-Rm6kcm2nWaILPIReejfra65DyeLr5po8UPVRwOvB75x07DwJnhCg7Watu2r7QJJupzDyYrf6NmHpDLS7LPqvIgGgQ4W_uv1v2_k8bD1o03phj_yF5_p6M9GUnZWRDTKqGke4kGUh57HrF7kgMikqgm0MjrA2nIPlcdcZRnt_siSLs9_NbWMQF6eGtp6LUiiWlAn7ePkcHcP0mn9D7VOYFdINk-kEf9EaXZXNm8foCnnEfcpnkFiPdFRGap9h3x7suzzo8rAqe14uYcI
APIリクエスト
取得したaccess_tokenを利用してAPIをコールしてみます。
curl -H 'Accept: application/json' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjJlNWYzOTExMTcyZmM5MTkxOTZhZTI1MGNmY2ZkOGNhNTExNzFmN2I1Y2E5M2I0OGE0ODFiNDQzOTlhNDAxNTBmNjM4OWJhNjFjMDBlYTY5In0.eyJhdWQiOiIzIiwianRpIjoiMmU1ZjM5MTExNzJmYzkxOTE5NmFlMjUwY2ZjZmQ4Y2E1MTE3MWY3YjVjYTkzYjQ4YTQ4MWI0NDM5OWE0MDE1MGY2Mzg5YmE2MWMwMGVhNjkiLCJpYXQiOjE1Mzg4Mjg4ODAsIm5iZiI6MTUzODgyODg4MCwiZXhwIjoxNTcwMzY0ODgwLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.ROGkKk_BRTCuW2pUrq7PegzNnrF1Bo3a6Q0-v3T_9s3AJ33ZtZWyuD6QSxVJpPFWxiRttkno-5kFiNk0Ne8okg3XUwA1WQqJwZMlXjn1A2LmYO2NZ-KihgfjXKkncYwxPi3VsE84chIPRfOFokpy5vcVMtV7ds7jkl3zThTks5AqTPDNwCvMK95cYuFmtUfY8f__FRlLvEU2qaTbHVt7UJbe-l_P1LZEhfkZDQcPDkddkGn0W_5Zwgk5VqEEJezv1W07Yrq7BiWGzqO227XWgbwwZT4S6BX2l9Yka8aQGdqUkW-zj3Eeq07gLyRTDdzRd2tICZGn6_sXoChXeT_uu6_f3sWSiS8nn1StMW_4zEfBW2lbb8H1VQzS4Y5SMUqwCnSvZ2OV1-nG_e0KPd9HJeCz9q5-Rm6kcm2nWaILPIReejfra65DyeLr5po8UPVRwOvB75x07DwJnhCg7Watu2r7QJJupzDyYrf6NmHpDLS7LPqvIgGgQ4W_uv1v2_k8bD1o03phj_yF5_p6M9GUnZWRDTKqGke4kGUh57HrF7kgMikqgm0MjrA2nIPlcdcZRnt_siSLs9_NbWMQF6eGtp6LUiiWlAn7ePkcHcP0mn9D7VOYFdINk-kEf9EaXZXNm8foCnnEfcpnkFiPdFRGap9h3x7suzzo8rAqe14uYcI' http://localhost:8000/api/user
APIレスポンス
ユーザー情報が取得できています。
{"id":1,"name":"user1","email":"user1@test.com","email_verified_at":null,"created_at":"2018-10-06 11:10:52","updated_at":"2018-10-06 11:10:52"}
Implicit Grant Token
いよいよ最後のImplicit Grant Tokenです。
準備
Implicit Grant Tokenを利用するには、AuthServiceProvider.phpにその旨、加筆します。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
Passport::routes();
+ Passport::enableImplicitGrant();
}
}
クライアントの生成
redirect_uriを指定する必要があるため、Auth Code用のクライアントを流用します(する必要があります)。
Tokenリクエスト
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client as Client;
$guzzle = new Client;
$query = http_build_query([
'client_id' => '3',
'redirect_uri' => 'http://localhost/callback.php',
'response_type' => 'token',
'scope' => '',
]);
header('Location: http://localhost:8000/oauth/authorize?'.$query);
Tokenレスポンス
上記のコードを実行すると、リダイレクトURL中にフラグメントとしてtokenが返されるようです。
http://localhost/callback.php#access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImQ0MzI3MWFmNjk3ZmJhMDIxM2U2NjUzZWU0MDgyNmU5NTlhYTRlMmYwM2QyNzFjZWNmODEwYzk0NjQxMjY2OGJmN2RmM2UwZTA4MGE3YzFiIn0.eyJhdWQiOiIzIiwianRpIjoiZDQzMjcxYWY2OTdmYmEwMjEzZTY2NTNlZTQwODI2ZTk1OWFhNGUyZjAzZDI3MWNlY2Y4MTBjOTQ2NDEyNjY4YmY3ZGYzZTBlMDgwYTdjMWIiLCJpYXQiOjE1Mzg4Mjk5MTgsIm5iZiI6MTUzODgyOTkxOCwiZXhwIjoxNTcwMzY1OTE4LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.32FUf_2iF75523QY1uDxG0sv4gWyDW5qbx9rJ1FdYDbbRSPPohyGf3SjSzXsAWNeFSDMuKoLNaeczOMQ_jY3dLd2D2KyU7RD75IM2ZFXFf1w9vzUBHoLv9AMpIuAMuAik7N3LJIyRrGKo1tKxuwNDitEdASQpOtm16io6pn1aUkzuyeJ8C_geugogOOp377WH4wKj4hRwM6GHQilUxcMKVu6XTsb8ZtqWXXv_LGQvxgcLH1koMAKisi5qn8lEeMI3AX6K19mWe2UruBjUFmyfsBKqoLNWNeOKD2O-IzCnPZkfp1eU88lQlDCln9RdM4du4C0lILwEKRATxwlxT-EEny7VP4pckbUX_hBzooD5S0imwHMQ89zE4t5T7Cxhi8LF2Vm1mvsNaOmbAzo4SUtgWa3J2-lcDfNC3m6hSYKEUkKNcIFZN_CWRQsPJmNgwU202OlmDhiJlP-Bk9j4X_6i6vq_l3x54KFJ8M6s6yPqLEUBXilouotS82r_BKsM1f5OMQFUAaMiFPHvp45R0nfsTnJsKHM6yhkprSWytP63SUGUtbDewUeMrjdXfrxCyhqGOO-bo8HcyPOVFF9hHqUzgoOELAKoJwpJvOmdueVTuQNqFXtak_H86K3ea02CJ9QXc_JHyxQRWPUK01RLY2yR-vV3677AeTCTNE2EJh5Aqk&token_type=Bearer&expires_in=31536000
なお、フラグメント値はサーバ側では取得できないため、JavaScriptで取得します。
<!doctype html>
<html>
<body>
Implicit Callback.
<script>
(function(){
var hash = window.location.hash;
alert(hash);
})();
</script>
</body>
</html>
なお、Client Credentials Grant Token同様、Implicit Grant Tokenでも個人レベルでの認証は行われません。
そのため、/api/client1は値を返しません。
APIリクエスト1
/api/user相当。
curl -H 'Accept: application/json' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImQ0MzI3MWFmNjk3ZmJhMDIxM2U2NjUzZWU0MDgyNmU5NTlhYTRlMmYwM2QyNzFjZWNmODEwYzk0NjQxMjY2OGJmN2RmM2UwZTA4MGE3YzFiIn0.eyJhdWQiOiIzIiwianRpIjoiZDQzMjcxYWY2OTdmYmEwMjEzZTY2NTNlZTQwODI2ZTk1OWFhNGUyZjAzZDI3MWNlY2Y4MTBjOTQ2NDEyNjY4YmY3ZGYzZTBlMDgwYTdjMWIiLCJpYXQiOjE1Mzg4Mjk5MTgsIm5iZiI6MTUzODgyOTkxOCwiZXhwIjoxNTcwMzY1OTE4LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.32FUf_2iF75523QY1uDxG0sv4gWyDW5qbx9rJ1FdYDbbRSPPohyGf3SjSzXsAWNeFSDMuKoLNaeczOMQ_jY3dLd2D2KyU7RD75IM2ZFXFf1w9vzUBHoLv9AMpIuAMuAik7N3LJIyRrGKo1tKxuwNDitEdASQpOtm16io6pn1aUkzuyeJ8C_geugogOOp377WH4wKj4hRwM6GHQilUxcMKVu6XTsb8ZtqWXXv_LGQvxgcLH1koMAKisi5qn8lEeMI3AX6K19mWe2UruBjUFmyfsBKqoLNWNeOKD2O-IzCnPZkfp1eU88lQlDCln9RdM4du4C0lILwEKRATxwlxT-EEny7VP4pckbUX_hBzooD5S0imwHMQ89zE4t5T7Cxhi8LF2Vm1mvsNaOmbAzo4SUtgWa3J2-lcDfNC3m6hSYKEUkKNcIFZN_CWRQsPJmNgwU202OlmDhiJlP-Bk9j4X_6i6vq_l3x54KFJ8M6s6yPqLEUBXilouotS82r_BKsM1f5OMQFUAaMiFPHvp45R0nfsTnJsKHM6yhkprSWytP63SUGUtbDewUeMrjdXfrxCyhqGOO-bo8HcyPOVFF9hHqUzgoOELAKoJwpJvOmdueVTuQNqFXtak_H86K3ea02CJ9QXc_JHyxQRWPUK01RLY2yR-vV3677AeTCTNE2EJh5Aqk' http://localhost:8000/api/client1
APIレスポンス1
何も返ってきません。が、認証エラーにもなりません。
(何も返らない)
APIリクエスト2
curl -H 'Accept: application/json' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImQ0MzI3MWFmNjk3ZmJhMDIxM2U2NjUzZWU0MDgyNmU5NTlhYTRlMmYwM2QyNzFjZWNmODEwYzk0NjQxMjY2OGJmN2RmM2UwZTA4MGE3YzFiIn0.eyJhdWQiOiIzIiwianRpIjoiZDQzMjcxYWY2OTdmYmEwMjEzZTY2NTNlZTQwODI2ZTk1OWFhNGUyZjAzZDI3MWNlY2Y4MTBjOTQ2NDEyNjY4YmY3ZGYzZTBlMDgwYTdjMWIiLCJpYXQiOjE1Mzg4Mjk5MTgsIm5iZiI6MTUzODgyOTkxOCwiZXhwIjoxNTcwMzY1OTE4LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.32FUf_2iF75523QY1uDxG0sv4gWyDW5qbx9rJ1FdYDbbRSPPohyGf3SjSzXsAWNeFSDMuKoLNaeczOMQ_jY3dLd2D2KyU7RD75IM2ZFXFf1w9vzUBHoLv9AMpIuAMuAik7N3LJIyRrGKo1tKxuwNDitEdASQpOtm16io6pn1aUkzuyeJ8C_geugogOOp377WH4wKj4hRwM6GHQilUxcMKVu6XTsb8ZtqWXXv_LGQvxgcLH1koMAKisi5qn8lEeMI3AX6K19mWe2UruBjUFmyfsBKqoLNWNeOKD2O-IzCnPZkfp1eU88lQlDCln9RdM4du4C0lILwEKRATxwlxT-EEny7VP4pckbUX_hBzooD5S0imwHMQ89zE4t5T7Cxhi8LF2Vm1mvsNaOmbAzo4SUtgWa3J2-lcDfNC3m6hSYKEUkKNcIFZN_CWRQsPJmNgwU202OlmDhiJlP-Bk9j4X_6i6vq_l3x54KFJ8M6s6yPqLEUBXilouotS82r_BKsM1f5OMQFUAaMiFPHvp45R0nfsTnJsKHM6yhkprSWytP63SUGUtbDewUeMrjdXfrxCyhqGOO-bo8HcyPOVFF9hHqUzgoOELAKoJwpJvOmdueVTuQNqFXtak_H86K3ea02CJ9QXc_JHyxQRWPUK01RLY2yR-vV3677AeTCTNE2EJh5Aqk' http://localhost:8000/api/client2
APIレスポンス2
認証自体は通過し、コンテンツが表示されます。
auth contents
おまけ
公開するルートを限定する
実際にはPassword Grant Tokenしか利用しない・・・という場合もあります。
AuthServiceProvider.phpの記述を変更することで、必要なルートだけを有効にできるようです。
public function boot()
{
$this->registerPolicies();
// Passport::routes();
Passport::routes(function($router){
$router->forAccessTokens();
// $router->forAuthorization();
// $router->forTransientTokens();
});
}
継続調査事項
いろいろ謎な仕様があるので継続調査します。
- Client(ID)とUser(ID)の関係
- Clientの発行単位(ユーザーに1クライアントか、1つのクライアントで複数ユーザーに対応していいか?)
- ユーザーひも付き型のクライアントでも他のユーザーからのリクエストでもTokenが変えるけど・・・(再確認)