Zenn
😀

JWT認証の流れをシーケンス図書いて整理してみた

に公開

こんにちは!株式会社バニッシュ・スタンダードの中村です。

ふとユーザーの認証/認可を一から作るならどうやって実現できるかな?と思い、自分の中の引き出しが少なかったので勉強も兼ねて整理してみることにしました。
認証/認可の仕組みを調べたところ、ベーシック認証、APIキー、OAuth 2.0、JWT(JSON Web Token)、セッションベース認証(Cookie+セッション)など調べれば色々あるらしいのですが、今回はJWTについて調べてみようと思います。
そして実際にシーケンス図を書いてみて、実際にユーザー認証の仕組みってどうなっているのか自分なりに整理してみようと思います。

まず最初に認証と認可ってなんなのでしょうか。

概念の整理

認証(Authentication)とは?

認証は 「誰がリクエストを送っているのか」 を確認する仕組み。
アプリケーションを利用する資格があるかどうかを最初に検証する。

認可(Authorization)とは?

認可は 「そのユーザーが特定のリソースや機能にアクセスできる?」 を決める仕組み。
アプリケーションのどの機能やデータにアクセスできるかを確認する。
認証が終わって認可の流れ。

Webアプリのユーザー管理をブログサービスで考えてみる

Authentication(認証)

目的:
ユーザーが正しいログイン情報を持っているかを確認する
フロー:

  1. ユーザーが メールアドレスとパスワードを入力する
  2. サーバーが入力情報を確認し、問題なければ JWT を発行(またはセッションを作成)。
  3. 以降のリクエストで JWT or セッションを送る ことで認証を維持

Authorization(認可)

目的:
ログインしたユーザーが、アプリのどの機能を利用できるかを決める。
例:
1.一般ユーザー
記事の閲覧→○
記事の投稿→×
記事の編集→×

2.投稿者
記事の閲覧→○
記事の投稿→○
自分の記事の編集→○
他人の記事の編集→×

3.管理者(Admin)
記事の閲覧→○
記事の投稿→○
全ての記事の編集・削除→○

このように認証が「Webアプリを使えるか?」なのに対し、認可は「Webアプリのどこまで使えるか?」を決める仕組みになります。

認証と認可の関係

  • 認証が成功しないと認可も意味がない(未ログインのユーザーには認可できない)
  • 認証は 1回 だが、認可は リクエストごとにチェックされる
  • 認証だけだと 全員が同じ権限 になるので、認可を組み合わせることで細かい制御が可能になる

疑問: 認証とAPI認証ってどう違うの?

  • 認証 → 「アプリケーションを使う資格があるか?」(人を認証)
  • API認証 → 「APIを使う資格があるか?」(クライアントを認証)

認証(Authentication)だと例えば

  • アプリのログインフォームで メールアドレス & パスワード を入力
  • OAuth 2.0 を使って Googleアカウントでログイン
  • 生体認証(指紋・顔認証)でスマホアプリにログイン
    つまり、認証は 人の身元を確認 するための仕組み。

API認証(API Authentication)は
「このリクエストは正規のクライアント(アプリ・サービス)からのものか?」 を確認すること。

対象として、APIを使うクライアントはWebアプリ、モバイルアプリ、サーバーなどがある。

API認証だと例えば

  • JWT (JSON Web Token) を使ったAPIリクエスト
  • APIキー(API Key) をヘッダーに含める
  • OAuth 2.0 のアクセストークン を使ってAPIにアクセス
    など。

API認証は APIが不正に利用されないようにする仕組み

APIを使うには、まず 認証(Authentication) が必要で、その後 API認証(API Authentication) によってリクエストごとにチェックされる。

実際の流れ(JWTを使う場合)

1.認証

  • POST /loginユーザーがログイン (認証)
  • サーバーが JWTを発行

2.API認証

  • ユーザーが GET /user-info を実行
  • クライアントが Authorization: Bearer {JWT}をヘッダーに付与
  • サーバーが JWTの署名を検証し、認証を確認
  • レスポンスを返す

API認証とは、APIリクエストごとに「正しいトークン」があるかをチェックする仕組み。

JWTの特徴

ステートレスな認証

JWTは自己完結型のトークンであり、認証情報をサーバー側で保存する必要がない。なのでサーバーがスケールアウトしやすく、ロードバランサーを介して複数のサーバーでリクエストを処理しやすくなる。

セキュリティ

JWTはBase64エンコードされた3つの部分(ヘッダー・ペイロード・署名)から構成され、署名(HMACやRSA)によって改ざんや偽造を防ぐ。

柔軟な情報の埋め込み

JWTには「クレーム」と呼ばれる情報を埋め込むことができる。これにより、単なるユーザーIDだけでなく、ユーザーの権限(roles)や有効期限(exp)などの情報も含めることができる。

実際にシーケンス図書いてみる

こんなシーケンス図を書いてみました。
HTTPSで使って通信は暗号化する前提で

JWTのステートレスの特徴を意識してみたのですが、これだと万が一アクセストークンが流出した時に期限が切れるまでは第三者に使い回されてシステムが利用されるリスクだったり、ユーザーがログアウトしてもアクセストークンが生き続けてしまうので、JWTを使うならこの辺りのリスクを許容できるか、っていうお話になるのかなと思いました。

上記の問題を回避するとしたらサーバー側でアクセストークンのブラックリストを持っておくなどがありそうですが、その分作りこみがいりそうなのと、JWTの特徴のステートレス性を損ないそうだなと思いました。JWT以外の選択肢も気になるのでまた時間を取って調べてみようと思いました。

最後に

今回、技術記事でなに書こうかな〜〜と思い、最近関心のあった認証/認可を調べて整理してみました。記事書きたいから、関心のあることを調べてキャッチアップするみたいな流れは結構いいなと感じました。

そして、認証/認可の世界は奥が深いと思いました。おそらく自分の理解が間違っていることもあると思います。もし当記事の内容で間違っている部分があればご指摘ください。

ここまで読んでいただきありがとうございました!

株式会社バニッシュ・スタンダード

Discussion

ログインするとコメントできます