Laravel PassportでOAuth2を用いた認証機能を作成しよう！

# はじめに

Laravel Passport は Laravel アプリケーションに OAuth2 サーバの機能を作成できるパッケージです。

https://laravel.com/docs/10.x/passport

本記事では Laravel Passport を使用して、OAuth2を用いた認証機能を作成します。

:::note warn
厳密には OAuth2 は "認可" で用いられる仕組みですが、Laravel の公式ドキュメントより "認証" の用途で使用されているように見受けられましたので、本記事では基本的に "認証" という用語に統一させて頂きます。
:::

# OAuth2 とは？

わかりやすく解説されている記事がありますのでそちらをご覧ください。私も記事を見て勉強させて頂きました。

https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be

https://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f


Laravel Passport では、以下の Grant が利用可能ですが、中には非推奨のものも存在します。

* Authorization Code Grant 
* Client Credentials Grant
* ~~Implicit Grant~~ → 非推奨
* ~~Password Grant~~ → 非推奨

特に Implicit Grant に関しては、セキュリティ面での問題も指摘されています。

https://www.sakimura.org/2012/02/1487/

したがって、今回は非推奨とされている Grant は利用せず、最も一般的と思われる **Authorization Code Grant** を用います。また、認可コード横取り攻撃のリスクを軽減するため、**PKCE** を用いた方法で作成します。

https://qiita.com/samiii/items/9574d1e237228c718cd6

# 完成イメージ

以下2つの Laravel プロジェクトを作成して、Authorization Code Grant を用いた認証を実際に試せる環境を構築します。

* リソースサーバ 兼 認証サーバ
* クライアントアプリ

## リソースサーバ 兼 認証サーバ

### 用途

OAuth2 サーバとしての役割を担うために作成する。
また、ユーザ管理の機能も有する想定とする。

### 画面
    
| 画面名 | 画面イメージ |
| --- | --- |
| ログイン画面 | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339770/db8fd868-84a5-4e40-afd6-3909f155730f.png" width="300" /> |
| マイページ画面<br />（ログイン直後の画面）| <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339770/63096faa-0f28-df12-a6ec-3925be974c07.png" width="300" /> |
| ユーザ情報確認画面 | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339770/2940e9c5-ac95-1e93-eb70-6ec61462293b.png" width="300" /> |
| ユーザ情報更新画面 | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339770/2bdbb78f-ae01-301c-70d8-7918a8cef4a8.png" width="300" /> |

### ルート

| HTTPメソッド | パス | 用途 |
| --- | --- | --- |
| GET | /oauth/authorize | 認可コードを発行する |
| POST | /oauth/token | アクセストークンを発行する |
| GET | /login | ログイン画面を表示する |
| GET | / | マイページ画面を表示する |
| GET | /user/{path?} | ユーザ情報確認／更新画面を表示する |
| POST | /login | ログイン処理を実行する |
| GET | /logout | ログアウト処理を実行する |
| POST | /user | ユーザ情報を更新する |
| GET | /api/user | ログインユーザ情報を取得する |
| DELETE | /api/token/{clientId} | 発行したトークンを取り消す |

## クライアントアプリ

### 用途

リソースサーバ 兼 認証サーバを用いた認証を行うために作成する。

### 画面

| 画面名 | 画面イメージ |
| --- | --- |
| ログインユーザ情報画面<br />※ 未認証の場合 | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339770/c59e8c1c-3fea-f163-01a0-6310934d3ed6.png" width="300" /> |
| ログインユーザ情報画面<br />※ 認証済みの場合 | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339770/34c7c41e-336d-098a-683d-ae1b1383a0bb.png" width="300" /> |

### ルート

| HTTPメソッド | パス | 用途 |
| --- | --- | --- |
| GET | /auth/redirect | OAuth サーバからのコールバック処理を実行する |
| GET | /auth/callback | OAuth サーバへのリダイレクト処理を実行する |
| GET | / | ログインユーザ情報画面を表示する |
| GET | /logout | ログアウト処理を実行する |
| GET | /api/user | ログインユーザ情報を取得する |

# 技術構成

どちらの Laravel プロジェクトにおいても以下の構成で作成します。

* PHP 8.2
* Laravel 10.x
* Vue.js 3.3
* Vue Router 4
* TailwindCSS
* MySQL 8.0

ただし、認証に用いるパッケージはそれぞれの目的に応じて異なるパッケージを使用します。
| プロジェクト名 | パッケージ | 目的 |
| --- | --- | --- |
| リソースサーバ 兼 認証サーバ | Laravel Passport | OAuth2 のサーバ機能を有するため |
| クライアントアプリ | Laravel Sanctum | SPA認証を行うため |


# 事前準備

* 以下の Laravel 10.x プロジェクトをそれぞれ新規作成済み
    * リソースサーバ 兼 認証サーバ
    * クライアントアプリ
* `.env` にデータベースの接続情報を設定済み

# 作成手順

非常に長くなってしまったので、記事を分割させて頂きました。

【リソースサーバ 兼 認証サーバ】
    [1. Laravel Passport のインストール](https://qiita.com/falya128/items/3b306194a5bad14ab582)
    [2. Laravel Passport の初期設定](https://qiita.com/falya128/items/3b306194a5bad14ab582)
    [3. ログイン画面の作成](https://qiita.com/falya128/items/3b306194a5bad14ab582)
    [4. マイページ画面の作成](https://qiita.com/falya128/items/3b306194a5bad14ab582)
    [5. ユーザ情報確認／更新画面の作成](https://qiita.com/falya128/items/ef8885b4fd902a05d8bc)
    [6. ログアウト処理の追加](https://qiita.com/falya128/items/ef8885b4fd902a05d8bc)
 
【クライアントアプリ】
    [7. トークンのリクエスト処理の追加](https://qiita.com/falya128/items/651daf3f4dd91ac70dcc)
    [8. Laravel Sanctum の初期設定](https://qiita.com/falya128/items/651daf3f4dd91ac70dcc)
    [9. ログインユーザ情報表示画面の作成](https://qiita.com/falya128/items/651daf3f4dd91ac70dcc)
    [10. ログアウト処理の追加](https://qiita.com/falya128/items/651daf3f4dd91ac70dcc)

【リソースサーバ 兼 認証サーバ】
    [11. Laravel Passport のルート登録](https://qiita.com/falya128/items/b73d91b0bde1fa65ad98)
    [12. トークン取消 API の作成](https://qiita.com/falya128/items/b73d91b0bde1fa65ad98)

# まとめ

実際に作成してみると大変でしたが、Laravel Passport があれば OAuth2 サーバを自力で作成できることがわかりました。
当初の希望としては Open ID Connect を用いて認証機能を作成したかったのですが、良い方法を見つけられなかったため、OAuth2 を用いて認証機能を作成しました。
セキュリティ面での問題やその他機能に関するご指摘などがあれば、コメントいただけますと幸いです。

# GitHub

完成版のプロジェクトはこちら

https://github.com/falya128/laravel-oauth2-server

https://github.com/falya128/laravel-oauth2-client