laravel8 Passport 調査して不思議に感じたこと


## 初めに
laravelを触り始めて２月ほど経ちますが、 
ここ数日 Passportを触ってみて面倒だな。と感じたことを残しておきます。

## 作成されるクライアントのIDが整数
phpmyadminで確認すると、IDがintでした。
シーケンス番号であれば問題ないのですが、実際に使用する際はIDを指定するので、intは困る。
google,facebookなどのSNSログインを実装すると知るのですが、client_idは英数字の羅列です。

ドキュメント記載の`php artisan passport:install --uuids`を実行するとユニークなIDを持ったテーブルを再構築できます。
![スクリーンショット 2021-10-11 14.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318237/5b218816-f66d-d417-6d92-a69fa2b27801.png)

しかし、この後 `php artisan passport:install`を実行すると
IDにデフォルト値がないとエラーが発生します。
どうやらコマンド実行時に使用されるメソッドは ユニークなIDを発行する機能が存在しません。
今回は直接passportライブラリに追記します。

``` php
//ClientRepository.php
public function create($userId, $name, $redirect, $provider = null, $personalAccess = false, $password = false, $confidential = true)
    {
        $client = Passport::client()->forceFill([
            'id' => (string) Str::orderedUuid(), //idにuuidを付与
            'user_id' => $userId,
            'name' => $name,
            'secret' => ($confidential || $personalAccess) ? Str::random(40) : null,
            'provider' => $provider,
            'redirect' => $redirect,
            'personal_access_client' => $personalAccess,
            'password_client' => $password,
            'revoked' => false,
        ]);

        $client->save();
}
```

再度コマンド実行することでクライアントを作成できます。

```

Which user ID should the client be assigned to?:
 > 

 What should we name the client?:
 > ******

 Where should we redirect the request after authorization? [http://localhost:8080/auth/callback]:
 > http:localhost:3000/callback.php

New client created successfully.
Here is your new client secret. This is the only time it will be shown so don't lose it!

Client ID: **********************************
Client secret: **********************************
```

## 使用しないルーティングを消すのが面倒だった。
複数の認証方法が使用できる為、RouteRegistrar.phpにルーティングが用意されています。
しかし、不要なルーティングの除外は設定として存在しません。

今回は、Passport.php RouteRegisterを上書きするディレクトリ[packages]を用意、
Composerに追記し、 dump-autoroadを実行し、
app/Providers/AuthServiceProvider に カスタマイズしたrouteを読み込みました。

```
//composer.jsonに追記
"autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/",
            "Custom\\": "packages/"   //追加
        }
    },
```
修正後、 `composer dump-autoload` を実行し useで読み込めるようにする

### 他の方がルートを限定する書き方公開されていました。
こちらのほうが楽です。
[公開するルートを限定する](https://qiita.com/zaburo/items/65de44194a2e67b59061#%E5%85%AC%E9%96%8B%E3%81%99%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%88%E3%82%92%E9%99%90%E5%AE%9A%E3%81%99%E3%82%8B)


## 用意されているPurgeコマンドが使いづらい。
- 無効・期限切れのトークンと認可コードを破棄する
- 無効なトークンと認可コードのみ破棄する
- 期限切れのトークンと認可コードのみ破棄する  

と用意されています。
しかし期限切れのトークンを削除するには、有効期限から本日から7日前を経過する必要があリました。
幅を持たせる為に7日前超過にしてるんですかね？
でも、発行されたexpired_atをwhereで検索するので、そこまで幅を持たせる必要があるのかな...

ドキュメント記載の有効期限を AuthServiceProvider::boot() 内に
`Passport::tokensExpireIn(now()->addMinutes(60)); `
を記載して変更しても実際のデータはしばらく残ります。

実際の運用状況で変わるかと思いますが、
config/passport.phpなどで柔軟に対応して欲しいです。
しかし、リフレッシュトークンからアクセストークンを再発行できるのでこのPurgeコマンドもどう使えばいいか悩みますね。

`php artisan passport:purge`コマンド実行時のコード

``` php
//PurgeCommand.php
public function handle()
    {
        $expired = Carbon::now()->subDays(7);

        if (($this->option('revoked') && $this->option('expired')) ||
            (! $this->option('revoked') && ! $this->option('expired'))) {
            Passport::token()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();
            Passport::authCode()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();
            Passport::refreshToken()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();

            $this->info('Purged revoked items and items expired for more than seven days.');
        } elseif ($this->option('revoked')) {
            Passport::token()->where('revoked', 1)->delete();
            Passport::authCode()->where('revoked', 1)->delete();
            Passport::refreshToken()->where('revoked', 1)->delete();

            $this->info('Purged revoked items.');
        } elseif ($this->option('expired')) {
            Passport::token()->whereDate('expires_at', '<', $expired)->delete();
            Passport::authCode()->whereDate('expires_at', '<', $expired)->delete();
            Passport::refreshToken()->whereDate('expires_at', '<', $expired)->delete();

            $this->info('Purged items expired for more than seven days.');
        }
    }

```

※whereDate()は日付単位での検索になるので、 where()を使用すると分単位で指定できました。


##　終わり
まだ、触ると疑問が出てきますが一旦これで終了します。
Laravel Passportを実際に使用しているサービスってあるんですかね。
ドキュメントだけでは少し不安です。

## 今回、参考にさせていただいた記事
[Laravel Passportの使い方まとめ](https://qiita.com/zaburo/items/65de44194a2e67b59061#%E5%85%AC%E9%96%8B%E3%81%99%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%88%E3%82%92%E9%99%90%E5%AE%9A%E3%81%99%E3%82%8B)
[Query Builder(クエリビルダー) – 各種where句の使い方]
(https://public-constructor.com/laravel-query-builder-where-clauses/#toc2)
[Laravel SQLの実行クエリログを出力する  > コンソール画面で表示できました。]
(https://qiita.com/ucan-lab/items/753cb9d3e4ceeb245341)
[]()