みなさん、こんにちは!ネットワークとWebの深淵を愛するインフラアーキテクトです。
日頃からAPIを叩いたり、ログイン認証の仕組みを作ったりしていると、必ず耳にするのが「OIDC(OpenID Connect)」ですよね。「なんだか難しそうな名前だな…」「JWTとかIDトークンとか、アルファベットの呪文がいっぱい出てきて頭がクラクラする!」そんな風に感じていませんか?
大丈夫です。一歩ずつ、身近な例えから紐解いていけば、決して恐ろしいものではありません。今回は、OIDCの心臓部である「IDトークンの構造と、それが偽物ではないかを見破る検証のステップ」を、郵便配達の世界に例えながら優しく解説していきます!
—
1. IDトークンってなに?身近な「手紙」に例えてみよう
Webサイトやアプリで「Googleアカウントでログイン」や「LINEでログイン」といったボタンを押したとき、裏側では何が起きているのでしょうか?
あなたが「私は〇〇です!」と名乗ったとき、認証サーバー(GoogleやLINEなど)は、「この人は間違いなく、我が社が身元を確認した〇〇さんです!」という特別な証明書を発行してくれます。これが、今回主役となるIDトークンです。
これは例えるなら、区役所が発行してくれる「印鑑登録証明書付きの封筒」のようなものです。
中身が誰についてのものか(名前や住所など)が書かれていて、さらに区役所のガッチリとした公印が押されているため、誰も中身を勝手に書き換えることができません。
OIDCの世界では、この「封筒」が JWT(JSON Web Token) という特別な形式で作られています。
—
2. IDトークンの構造:JWTの3層パケットを解剖する
JWT形式のIDトークンは、実はものすごくシンプルで、ドット(.)で区切られた3つのパーツでできています。
[ヘッダー(Header)] . [ペイロード(Payload)] . [署名(Signature)]
この3つのパーツが、それぞれどんな役割を持っているのか、順番に見ていきましょう!一歩ずつ理解していきましょうね。
① ヘッダー(Header):封筒の「表書き(利用する道具の指定)」
ヘッダーには、「この封筒を作るのに、どんなペン(アルゴリズム)を使ったか」という情報が書かれています。
{
"alg": "RS256", // 署名に使った暗号化のアルゴリズム(RSA + SHA-256)
"typ": "JWT" // トークンの種類(これがJWTであることを示す)
}
「あ、今回はこの暗号方式ね」と、受け取る側が最初に確認するためのラベルだと思ってください。
② ペイロード(Payload):手紙の「中身(ユーザーの身分証明)」
ここが一番重要な、ユーザーのプロフィールや「いつまで有効か」といった情報が詰まっている場所です。JSON形式で書かれています。
{
"iss": "https://accounts.google.com", // 発行者(誰がこの手紙を書いたか)
"sub": "1234567890", // ユーザー固有のID(この世にたった一人の識別子)
"aud": "my-awesome-app-client-id", // 対象者(誰宛ての手紙か)
"exp": 1719830400, // 有効期限(いつまでこの手紙が使えるか)
"iat": 1719826800 // 発行日時(いつこの手紙が書かれたか)
}
英語の略称が出てくると少し身構えてしまいますが、中身を日本語に訳せばただの「お墨付きのプロフィールカード」です。
③ 署名(Signature):区役所の「割印・公印」
一番大事なのがこの「署名」です。
もし、悪意ある第三者が途中でペイロード(中身)のデータをコソコソと書き換えたとします。そのとき、この署名が「おい、中身が書き換えられてるぞ!」と一発でバレるようにするための、暗号化されたシールの役割を果たします。
—
3. なぜ検証が必要なの?〜ネットワークの安全を守る関所〜
さて、発行者からあなたのアプリにこのIDトークンが届きました。
「やったー!ログイン成功だ!」と、そのまま信じて中身を読んでしまうのは、実はインフラエンジニアとしては大NG(重大なセキュリティホール)です。
なぜなら、ネットワークの途中で誰かが偽物のトークンを送りつけてきたり、とうに期限切れになった古いトークンを使い回しているかもしれないからです。
ここで、アプリ側(受け取る側)で必ず行うべき「3つの検証チェックポイント」を整理しましょう。
1. 発行者(iss)のチェック:本当に信頼できる機関(例: Google)から届いたものか?
2. 対象者(aud)のチェック:その手紙、本当に「うちのアプリ宛て」のものか?(他のアプリ宛ての使い回しじゃないか?)
3. 有効期限(exp)のチェック:タイムリミットが切れていないか?(過去の古い切符になっていないか?)
4. 署名の検証:中身が途中で改ざんされていないか、公開鍵を使って数学的に裏付ける。
—
4. 実装コードで見る!IDトークンの検証ロジック(Python版)
百聞は一見に如かず。実際にPythonの代表的なライブラリ PyJWT を使って、IDトークンを安全に検証するコードを見てみましょう。実務のWebアプリケーションでもそのまま参考にできる書き方になっています。
import jwt
from jwt.exceptions import ExpiredSignatureError, InvalidTokenError
import requests
def verify_id_token(id_token: str, client_id: str):
"""
受け取ったIDトークンが本物か、安全に検証する関数です。
"""
try:
# 1. 署名検証に必要な「公開鍵」をGoogleなどの発行者から事前に取得する想定
# (実際にはJWKSエンドポイントから取得しますが、ここでは簡略化しています)
issuer_url = "https://accounts.google.com"
# 2. PyJWTライブラリを使って、署名・有効期限・宛先などを一気に検証します
# ここで `exp` や `aud` のチェックも自動で行われます!
decoded_payload = jwt.decode(
id_token,
options={
"verify_signature": True, # 署名の改ざんチェックを行う
"verify_exp": True, # 有効期限切れになっていないかチェックする
"verify_aud": True # 当て先(クライアントID)が合致するかチェックする
},
audience=client_id, # 自アプリのクライアントIDを指定
issuer=issuer_url, # 期待する発行者を指定
algorithms=["RS256"] # 許可するアルゴリズム
)
print("検証成功!安全なIDトークンです。")
print(f"ログインしたユーザーのID (sub): {decoded_payload.get('sub')}")
return decoded_payload
except ExpiredSignatureError:
# 有効期限が切れていた場合の例外処理
print("エラー: IDトークンの有効期限が切れています。再ログインが必要です。")
return None
except InvalidTokenError as e:
# 署名が不正、または中身が改ざんされていた場合の例外処理
print(フローerr("エラー: 不正なIDトークンです(改ざんの可能性があります): %s", e))
return None
コード内のコメントにも書いた通り、ライブラリが自動的に exp(有効期限)や aud(宛先)、そして 署名(Signature) のつじつまを隅々までチェックしてくれます。これなら、ネットワークの海を渡ってきた怪しいパケットからも、しっかりとアプリケーションを守ることができますよね。
—
5. まとめ
今回は、OIDCにおけるIDトークンの構造と、安全性を担保するための検証ロジックについて解説しました。
- IDトークン は、ユーザーの身分を証明する「区役所の公印付きの封筒(JWT)」のようなもの。
- 構造は [ヘッダー].[ペイロード].[署名] の3つのドット区切りでできている。
- アプリで受け取ったときは、「発行者(iss)」「対象者(aud)」「有効期限(exp)」、そして「署名」の検証 を必ず行うのが鉄則。
インフラやセキュリティの世界は、一見すると難解な用語のオンパレードですが、一つひとつの部品が「現実世界のどんな仕組みに対応しているのか」を紐解いていくと、非常に美しく合理的にできていることが分かります。
ぜひ、日々の開発やインフラ設計の現場で、この「パスポートと関所の関係」を思い出して安全な認証基盤を築いていってくださいね!それではまた次回の技術解説でお会いしましょう。
コメント