- JWTは JSON Web Token の略で、認証済みトークンのための標準。
- JWTはヘッダー、ペイロード、署名またはメッセージ認証コードで構成される。
- 検証鍵を持つ人は、ペイロードの真正性を確認できる。
JWTの一般的な利用パターン
- JWTには、発行者、受信者、主体、有効期限などの情報が含まれる。
- 受信者はトークンの真正性を確認した後、有効期限が切れていないことを確かめ、主体を認証済みユーザーとして扱う。
JWTの利点
- JWTの主な利点は、受信者がユーザーデータベースに接続しなくてもトークンの真正性を確認できる点にある。
- 大規模な導入環境では、認証サービスが中央ユーザーデータベースにアクセスする唯一のサービスになり得る。
ログアウトとセッション無効化の問題
- 認証トークンの寿命は短くあるべき。たとえば最大 5 分。
- クライアントには、新しい認証トークンを要求できるリフレッシュトークンも発行される。
- リフレッシュトークンが実質的にセッショントークンの役割を果たす。
JWTが不要な場合
- ログアウトを実装するには、有効な JWT の許可リスト、または失効した JWT の拒否リストを維持する必要がある。
- ユーザーをブロックするには、データベースで「ユーザー有効」フラグを確認しなければならない。
- ユーザーオブジェクトと他のオブジェクトの間に追加の関係が必要になる。
- データベースに関連する処理を行う。
結論
- 上記の条件のいずれか一つでも当てはまるなら、JWTは必要ない。
- 一般的な不透明なセッショントークンを使い、データベースに保存するほうがよい。
- JWTの欠点を避け、複雑さを減らせる。
GN⁺の意見
- JWTは大規模サービスには適しているが、ほとんどの小規模サービスには過剰な複雑さをもたらす可能性がある。
- 一般的なセッション管理メカニズムで、ほとんどの Web アプリケーションには十分である。
- JWTを使うと、ログアウトやセッション無効化のような機能を実装するのが難しくなることがある。
- JWTの利点を活かすには、サービスの規模と要件を慎重に検討する必要がある。
- 他の代替案として、OAuth2 のような認証フレームワークを検討できる。
8件のコメント
さまざまなクライアント認証が必要な場合、JWT を使うことで得られる利点は多くありました。
ただし、拡張性とセキュリティは常に異なる方向を向いているため、セキュリティがとりわけ重要であれば、別の方法を使うほうがよいと思います。
個人的には、JWTトークンは公開されても問題ない一時データをブラウザ経由でシステム間でやり取りするときに使う程度で、
認証に使われる個人情報を含むトークンは opaque トークンを使うほうがよいと思います..
個人的な経験に照らすと、MVP を作る際には JWT に利点がありました。
たとえば、一人で作って運用するサービスであれば、急な要求による企画コストを下げられるという考えです。どうしても、最初に立てたデータの関係が 1〜2 か月後には完全に変わってしまうことがあるので、企画が明確に固まっていない状態では、(auth に関するものに限れば)むしろ JWT のペイロードを optional field の形で構成して機能実装をしておけば、企画側でドメイン分離やサービス分離の作業をしなくても、ひとまずモノリシックなサービスの中でドメインだけを簡単に分離する形で実装したうえで、市場テストまで持っていけた記憶があります。(その後でサービスを分離する流れに進むわけです。あるいはやめるか。)
とはいえ、作ろうとしているサービスのドメインごとにも違う気がします。そのプロジェクトは、リアルタイムサービスの中でもサードパーティとの結合度が高いプロジェクトだったので……やはり素早く実装していくと DB に膨大な量のドキュメント / row が積み上がったときに管理コストが大きくなりそうだ、という考えのもとで進めていた記憶があります。
もちろん、素早く作ることに集中するならセッション方式のほうがよいと思います。(初期段階では複数サービス間のカップリングもそれほど強くないので、作り直すのも楽ですし)他チームメンバーが参加したときの引き継ぎコストも少ないですから。
当時は少しの間あれこれ悩みましたが、今振り返ってみると、実際にはどちらの方式で実装していてもプロジェクトへの影響はそれほど深刻ではなかった気がします。
個人的には、API gateway を使うときに auth の実装を JWT にするとメリットがあると思っているのですが、小規模なサービスで JWT が持つ利点にはどのようなものがあるのか気になります。JWT に含めるユーザー情報を頻繁に変更するケースのことをおっしゃっているのでしょうか?
おっしゃっていることと大枠では同じです。ただ、ユーザー自体のモデリングが変わって情報を頻繁に変更しなければならないというよりは、新しい機能の追加やサードパーティーツールを使う新しいサービスが追加情報を要求するときに、オプションとして付け足すケースに近かったです。(もう少し言うと、潜在的に auth を API gateway のようなもので管理単位を分離するかどうか、あるいはそれに準ずる役割をするサーバーが1つあるかどうか、という微妙な状況の中で……)
もう少し具体的に例を挙げると、A というサービスをメインで進めていた状況でした。MVP だったので、決済情報や認証済みユーザーかどうかといった情報だけをユーザーテーブルに持っていました。ところが、ユーザーごとに異なる認証情報が必要でなければ利用できないサービス B と C を追加してほしい、という要望が入ってきた状況でした。その中でもさらに、B は A というサービスの中に組み込まれるかどうかも決まっておらず、C はなくなる可能性もあったので、軽くテストしたいという状態でした。(プラン管理機能は、言わなくても追加しておいたほうが無難だったでしょうし)。それに加えて、B、C を既存の A サービスを提供している Web サービスページで一緒に使ってみる形で始めたいとも考えていました。運用中のサービスという特性上、プラン管理テーブル(あるいは汎用的な認証関連テーブル)を作って、サービスごとにドメイン関係を設計してマッピングして実装する前までは、複数のテーブル参照(あるいはコレクション参照)が避けられない状況でした。これが、プロジェクトを整理してくれる人がいる状況であれば、何度か会議をして、いったい解決したい問題は何で、欲しい機能は何なのかを鋭く絞り込めればよかったのですが、そうなる保証はありませんでした。また、いつこうした負債を回収できるのかも不透明でした。なので、こういうことが起こりそうな兆候は A というサービスのローンチ前から見えていて……最初の構成を考えるときに、auth 時の参照コストや今後の管理コストをできるだけ抑えられる形にしようと考えた結果、JWT にしました。ほかにも細かい似たようなことが本当に多かった気がします。
ただ、コメントの最後で触れた通り、実際のところ何で実装していても、プロジェクト自体にはそこまで大きな影響はなかった気もします。セッションで実装していたとしても、セッションなりのやり方を見つけていたと思います。むしろ、開発者が他職種の仕事までやらなければならない状況や、コミュニケーションコストが発生し続ける状況にずっとさらされていたことのほうが、はるかに致命的だったと思います.
モノリス構造に適しているとしても、一部のサービスを分岐させたり拡張の岐路に立ったりするとき、JWTとセッションベースのロジックには明確な違いが見えてきます。単なる認証手続きではなく、内部ロジックの使い勝手という点でも、データの出所を扱う手法は変わってくるはずですが、小さなサービスというコンテキストをどの基準で適切だと判断すべきなのか、よく分かりません。すべてのサービスは必ず小さいという前提なのか。大きなサービスは難しいという前提なのか、分かりません。ですが、私たちが作るサービスには常に、どのような状況になるか分からなくても、なお有用なコンテキストを支えられる構造を最低限備えておくべきではないかと思います。小さなサービスという前提は、ただこれからも小さいままであるだけのように思えます。
Hacker Newsの意見
Hacker Newsコメント要約