実務でフロントエンドとバックエンドを切り離したSPA(SSG)を開発することになり、

SPAでの認証ってどうやるのが良いんだろ?
と調べていたらLaravelにはLaravel Sanctum(サンクタム)というSPA向けの軽量認証システムを提供する機能があることを知ったのでそれについて色々調べた結果をまとめておこうと思います。
- この記事は自分用のメモみたいなものです。
- 色々調べた中で有益な記事がたくさんあったので所々記事の中身を引用しています。
- 技術記事の他に僕自身が購入している技術書の内容も一部参考にしています。
- 参考記事・技術書は記事の最後に載せています。
Laravelの学習にオススメの教材はこちらにまとめています。


Laravel Sanctumとは
Laravelの公式ドキュメント(リンク)にはこのように紹介されています。
Laravel Sanctum provides a featherweight authentication system for SPAs (single page applications), mobile applications, and simple, token based APIs. Sanctum allows each user of your application to generate multiple API tokens for their account. These tokens may be granted abilities / scopes which specify which actions the tokens are allowed to perform.
https://laravel.com/docs/8.x/sanctum
公式ドキュメントの和訳サイト「ReaDouble」(リンク)ではこのように書かれています。
Laravel Sanctum(サンクタム、聖所)は、SPA(シングルページアプリケーション)、モバイルアプリケーション、およびシンプルなトークンベースのAPIに軽い認証システムを提供します。Sanctumを使用すればアプリケーションの各ユーザーは、自分のアカウントに対して複数のAPIトークンを生成できます。これらのトークンには、そのトークンが実行できるアクションを指定するアビリティ/スコープが付与されることもあります。
https://readouble.com/laravel/8.x/ja/sanctum.html
まず、Laravel Sanctumとは
SPA(シングルページアプリケーション)、モバイルアプリケーション、およびシンプルなトークンベースのAPIに軽い認証システム
ということですね。
Laravelに新しく搭載された機能ではあるものの、それ自体は認証システムを提供してくれているだけというか認証を手軽に実装できるパッケージ的なものなのでそれぞれの認証方式の違いを理解した方が良い気がします。
というわけでその提供してくれている認証方法について理解していきます!
Laravel SanctumはLaravel7.xで追加された新機能ですが、当時はLaravel Airlockという名前だったようです。
(商標権的な話でLaravel8.xから名前が変わったとのこと)
導入方法
まずはこの2つのコマンドを実行。
# Composerパッケージインストール
composer require laravel/sanctum
# Laravel Sanctum用の設定ファイルとトークン保存用のマイグレーションファイルの自動作成
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
後者のコマンド実行時に作成されるマイグレーションファイルは後述するSPA認証では使用しない。
提供する認証の仕組み
以下2つの認証方式を提供するとのこと。
- APIトークン
- SPA認証
SanctumをAPIトークン認証のみ、またはSPA認証のみに使用することはまったく問題ありません。Sanctumを使用しているからといって、Sanctumが提供する両方の機能を使用する必要があるわけではありません。
https://readouble.com/laravel/8.x/ja/sanctum.html
基本的に上記どちらかの認証方法を使うという選択で問題ないです。
それぞれまとめていきます。
APIトークン
OAuthの複雑さなしに、ユーザーにAPIトークンを発行するために使用できるシンプルなパッケージです。
この機能は、「パーソナルアクセストークン」を発行するGitHubやその他のアプリケーションに触発されています。たとえば、アプリケーションの「アカウント設定」に、ユーザーが自分のアカウントのAPIトークンを生成できる画面があるとします。Sanctumを使用して、これらのトークンを生成および管理できます。これらのトークンは通常、非常に長い有効期限(年)がありますが、ユーザーはいつでも手動で取り消すことができます。
Laravel Sanctumは、ユーザーAPIトークンを単一のデータベーステーブルに保存し、有効なAPIトークンを含む必要がある
https://readouble.com/laravel/8.x/ja/sanctum.htmlAuthorization
ヘッダを介して受信HTTPリクエストを認証することでこの機能を提供します。
上記内容を簡単にまとめます。
- ログインしたユーザーがAPIトークンを発行する
- 発行したトークンはDBに保存する
- GitHubのアクセストークン認証をインスパイアしている
- トークンの発行(生成)や管理が容易にできる
- トークンの有効期限はとても長いが、ユーザーはいつでも手動で消すことができる
- 認証にはリクエストのヘッダーを使用するため、Cookieなどは一切利用しない
認証のざっくりした流れは以下のとおりです。
- データベースにトークン保存用の単一のテーブル(personal_access_tokens)を作成する(※マイグレーションファイルは前述のコマンド実行時に作成済み)
- ユーザーがログインに成功した時にトークンを発行(トークンはランダムの40桁の文字列をsha256のハッシュアルゴリズムでハッシュ化したもの)
- 発行したトークンをpersonal_access_tokensテーブルに保存
- 発行したトークンをユーザーに知らせる
- トークン認証が必要なルーティングには
->middleware('auth:sanctum')
を定義する - リクエストが来た時にミドルウェアでリクエスト中の
Authorization
ヘッダーに設定されたトークンとデータベースのトークンの値を照合しユーザーを識別する(トークンがそもそもない場合、一致するトークンがない場合は401エラーを返す) - トークンの照合に成功したユーザーは
->middleware('auth:sanctum')
内のルーティング処理を続行する
視覚的にもわかりやすいように図で表してみました。
(※上記の番号とは一致していません)


ステータスコード401(Unauthorized)は適切な認証情報を持たずにリソースにアクセスしようとしたことを示します。
Laravel SanctumのAPIトークンの仕組み、と書きましたが一般的なトークン認証もこんな感じかと思います。
ここで注意点ですが、
SPAの認証にこのAPIトークンを使うべきではない
ようです。
こちらの記事参考:JWTは使うべきではない 〜 SPAにおける本当にセキュアな認証方式 〜
上記記事に書いていますが、SPAの認証にAPIトークンを使うべきでない理由はセキュリティ面に不安があるからです。
この方式の場合、APIトークンをクライアント(SPA)で保存する必要があるのですが、保存場所の選択肢としてローカルストレージくらいしかありません。
そしてローカルストレージはJavaScriptで簡単に読み込むことができます。
localStorage.getItem('キー');
悪意あるユーザーからローカルストレージからトークンを取得され、ログイン済みのユーザーになりすまして認証が必要な処理を不正に行われてしまう可能性がある。つまりセキュリティ面の理由から適していないということですね。
SPAの場合は次のSPA認証を使うのが望ましいみたいです。(まあ名前的にも適してそうですねw)
SPA認証
SPA認証がReact(Next.js)、Vue.js(Nuxt.js)で作成したSPA(Single Page Application)の認証に適した方式です。
Laravelを利用したAPIと通信する必要があるシングルページアプリケーション(SPA)を認証する簡単な方法を提供するために存在します。これらのSPAは、Laravelアプリケーションと同じリポジトリに存在する場合もあれば、Vue CLIまたはNext.jsアプリケーションを使用して作成されたSPAなど、完全に別個のリポジトリである場合もあります。
この機能のために、Sanctumはいかなる種類のトークンも使用しません。代わりに、SanctumはLaravelの組み込みのクッキーベースのセッション認証サービスを使用します。通常、SanctumはLaravelの「web」認証ガードを利用してこれを実現します。これにより、CSRF保護、セッション認証の利点が提供できるだけでなく、XSSを介した認証資格情報の漏洩を保護します。
Sanctumは、受信リクエストが自身のSPAフロントエンドから発信された場合にのみクッキーを使用して認証を試みます。Sanctumが受信HTTPリクエストを調べるとき、最初に認証クッキーをチェックし、存在しない場合は、Sanctumは有効なAPIトークンの
Authorization
ヘッダを調べます。Note: 認証を行うには、SPAとAPIが同じトップレベルドメインを共有している必要があります。ただし、異なるサブドメインに配置しても構いません。さらに、必ずリクエストへ
https://readouble.com/laravel/8.x/ja/sanctum.htmlAccept: application/json
ヘッダを付け、送信してください。
こちらも要点をまとめます。
- 認証にトークンは使用しない(トークン保存用のテーブルも作成する必要がない)
- Laravelに標準搭載されているCookieベースのセッション認証を使用する
web
認証ガードを利用することでCSRF、XSS等への対策ができる(セキュリティ対策)- SPA(フロント)から受信したリクエストのCookieを読み込んで認証を試す
- Cookieをチェックし、存在しない場合は
Authorization
ヘッダーのAPIトークンを調べる - SPA認証を行うSPAとAPIは同じトップレベルドメインであること(トップレベルドメインが同じであれば異なるサブドメインでも可)が条件
認証のざっくりした流れは以下のとおりです。
config/sanctum.php
にLaravelセッションクッキーを使用して「ステートフル」な認証を維持するドメインを定義する- apiミドルウェアグループにsactumミドルウェアを追加する。→SPAからのリクエストをLaravelのセッションクッキーを使って認証できるようにする&サードパーティまたはモバイルアプリケーションからのリクエストをAPIトークンを使用して認証できるようにする。
- SPAのログインページで初めに
/sanctum/csrf-cookie
にリクエストを送信して、アプリケーションのCSRF保護を初期化する。(この処理でLaravelは現在のCSRFトークンを含むXSRF-TOKEN
クッキーをセットする) - ログイン成功後、Laravelがクライアントにセッションクッキーを発行し、後続の処理はこのセッションクッキーを介して自動的に認証される。(ログイン、後続の処理でのリクエスト時にはCSRF保護の初期化に発行された
XSRF-TOKEN
クッキーの値をX-XSRF-TOKEN
ヘッダで送信する限り、後続のリクエストは自動的にCSRF保護が行える) - セッションの期限切れになった状態で認証が必要なAPIエンドポイントにリクエストすると401 or 419エラーを返す。(SPAでログインページにリダイレクトさせる)
Note: 独自の
https://readouble.com/laravel/8.x/ja/sanctum.html/login
エンドポイントを自由に作成できます。ただし、標準のLaravelが提供するセッションベースの認証サービスを使用してユーザーを認証していることを確認する必要があります。通常、これはweb認証ガードを使用することを意味します。
Laravel SanctumのSPA認証でのログイン処理は上記にもあるとおり、自由に作成することができます(といってもLaravelの標準的なセッションベースの認証機能を使う必要はあります)が、Laravel Fortifyという機能を使って実装することもできます。
Laravel FortifyはLaravelのフロントエンドに依存しない認証バックエンドの実装です
https://readouble.com/laravel/8.x/ja/fortify.html



Laravel Fortifyは初めて知った…
SAP認証は基本的なセッション+Cookieの認証方法と同じですが、こちらも図にしておきます。
(※認証の流れで書いた番号と図中の番号は一致しません)


ステータスコード401(Unauthorized)は適切な認証情報を持たずにリソースにアクセスしようとしたことを示します。また、419はRFCが定めるステータスコードにはなく、Laravelで独自に定義されたステータスコードです。419エラーになるケースはCSRFトークン周りのエラー。(例えばGET以外のリクエストでCSRFトークンが送られていないとか)


繰り返しになりますが、React/Next.jsやVue.js/Nuxt.jsによるSPAのバックエンドでLaravel APIを使う場合は認証にはSPA認証を採用するのが推奨されています。
Next.js+LaravelのSPA認証の実装方法もまとめています。


最後に
Laravel Sanctumについて公式ドキュメントベースで色々調べました。
やはりLaravel Sanctumを理解するというより、提供している認証システムのことを理解することの方が重要ですし、認証周りって意外とフワッとした感じだったのでこの機会にAPIトークン認証やSPA認証についてしっかり深掘りすることができてよかったです。
最後に参考記事をいくつか載せていますが、ネットに有益な情報がたくさん転がっているのでとてもありがたかったですm(__)m
参考記事・技術書
- Laravel Sanctum でSPA(クッキー)認証する
- API認証に使えるLaravel SanctumのToken APIを完全理解
- JWTは使うべきではない 〜 SPAにおける本当にセキュアな認証方式 〜
- Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)
- PHPフレームワーク Laravel Webアプリケーション開発 バージョン8.x対応
コメント
コメント一覧 (1件)
[…] 【Laravel8.x】Laravel Sanctumについて色々調べたのでまとめておく […]