はじめに
そろそろ表面上の理解から脱却しOIDCを腹落ちさせたい、と思いPythonで処理を実装してみることにしました。
本記事は実装前に、ChatGPTの助けを借りながら OpenID Connect Core 1.0 日本語訳 を読んで認証フローを整理したものになります。IdP側の処理については省略している部分がありますのでご了承ください。
2025/12/24 時点
本記事にPythonの実装内容は含まれません
実装の過程で誤りなどに気づいた場合、本記事の内容を訂正する可能性があります
概要
OIDC(OpenID Connect)は OAuth 2.0を拡張した認証プロトコルです。OpenID Connect Coreでは、以下と説明されています。
Client が Authorization Server の認証結果に基づいて End-User のアイデンティティを検証可能にする.
本記事では、Client = Pythonアプリ、Authorization Server = Google、End-User = アプリのユーザーとなります。この場合、Googleは一般的にIdP(Identity Provider)と表現されることもありますが、今回はドキュメントの記載に従ってAuthorization Serverとします*。
*より正確には、OpenID Provider (OP)と表現されます
認証フロー(Googleとアプリと私)
OIDCの認証フローについて、以下の登場人物の間でどのようなやりとりが発生するのかざっくり流れを整理します。
- ユーザー(私):ログインしたい
- アプリ(Client):ユーザーの認証を行いたい
- Google(Authorization Server):認証を行い、その結果をアプリに返す
OIDCの大まかな流れは以下になります。
| No | 通信元 → 通信先 | 内容 |
|---|---|---|
| 0 | ユーザー → アプリ | ユーザーはアプリ上で「Googleでログイン」を行う |
| 1 | アプリ → Google | アプリがGoogleに認証リクエストを送信し、ユーザーをGoogleへリダイレクトする |
| 2 | ユーザー → Google | ユーザーはGoogleアカウントでログイン(認証)を行う |
| 3 | Google → アプリ | 認証後、Googleがアプリに認可コードを返す |
| 4 | アプリ → Google | アプリは認可コードをGoogleに送り、IDトークンとアクセストークンをリクエストする |
| 5 | Google → アプリ | Googleは認可コードを検証し、IDトークンとアクセストークンをアプリに返却する |
| 6 | アプリ | 取得したIDトークンを検証する |
| 7 |
アプリ → Google (オプション) |
取得したアクセストークンを使ってユーザー情報をリクエストする |
| 8 |
Google → アプリ (オプション) |
アクセストークンを検証し、ユーザー情報を返却する |
※厳密には No.1 以降がOIDCの認証フローとして定義されています
OpenID Connect Coreに登場する用語
Pythonでアプリ側の処理を実装するために、次のセクションではより具体的な処理に落とし込んでいきます。この時、エンドポイントやらトークンやら複数登場しますので、先に用語を整理しておきます。
なお、この表には本記事では特に登場しない用語も含みます。OpenID Connect Coreを読むにあたり、自分用にメモした内容ですので、ドキュメントを読まれる方の参考になればと思い残しています。
| 用語 | 意味 |
|---|---|
| Authorization Server | 認証を行い、認可を発行したあとアクセストークンを発行するサーバー |
| OP (OpenID Provider) | 認証を行えるAuthorization Serverのこと |
| Client | 保護されたリソースへのリクエストを代理で行うアプリケーション |
| User Agent | デバイス上でClientを実行させるもの。Webブラウザーなどを指す |
| RP (Relying Party) | OpenID Providerにリクエストを行うClient |
| 認可エンドポイント (Authorization Endpoint) |
認証のリクエスト先 OpenID Providerが提供する |
| ディスカバリーエンドポイント | 各種エンドポイントなど、OpenID Providerの設定情報を公開するエンドポイント OpenID Providerが提供する |
| 認可コード (Authorization Code) |
OpenID Providerによる認証後、発行されるコード |
| トークンエンドポイント (Token Endpoint) |
認可コードの送信先であり、IDトークン・アクセストークンのリクエスト先 OpenID Providerが提供する |
| IDトークン | 認証結果を示すJWT |
| アクセストークン | 認可を表す文字列 |
認証フローの詳細
OIDCの認証フローとして、以下の3種類が定義されています。今回は、標準的に利用されている「**Authorization Code Flow」を取り扱います。
- Authorization Code Flow
- Implicit Flow
- Hybrid Flow
では、登場人物のやりとりを詳細化しながら、実装方法について整理していきます。
⓪ ユーザー → アプリ
ユーザーがログインページにアクセスし、「Googleでログイン」ボタンをクリックする
① アプリ → Google
ユーザーがGoogleアカウントでの認証を選択したら、アプリはGoogleに対して 「認証リクエスト」を作成・送信します。
「認証リクエスト」は、Googleの「認可エンドポイント(URL)」に対して必要なリクエストパラメータを含めた形で送信されます。認証はユーザーとGoogle間で直接行われるため、アプリは「認証リクエスト」の送信と同時に、ユーザーに表示する画面を「認可エンドポイント」にリダイレクトします。
以下は、アプリからのリダイレクトレスポンスの例です。
HTTP/1.1 302 Found
Location: <認可エンドポイント>? #以降リクエストパラメータ
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
アプリの実装処理:「認証リクエスト」の作成・送信
→ 認可エンドポイント・リクエストパラメータをもとに、ユーザーをリダイレクトするURLを生成
アプリが「認証リクエスト」を作成するためには「認可エンドポイント」のURLを事前に知っている必要があります。Googleの場合、「ディスカバリードキュメント」にアクセスすることで、「認可エンドポイント」のURLを取得できます。
ディスカバリードキュメントのURLは以下で固定されています。
https://accounts.google.com/.well-known/openid-configuration
{IdPごとの固有の値}/.well-known/openid-configuration は一般的にディスカバリーエンドポイントと呼ばれ、他のIdPでもディスカバリーエンドポイントにアクセスすることで、各種エンドポイントのURLなどを知ることができます。
②ユーザー → Google
ユーザーは認可エンドポイントにリダイレクトされ、Googleのログイン画面で認証を行います。アプリはユーザーの認証情報を扱いません。
このときGoogleはユーザーに対して、「ユーザーのデータをアプリに送信すること」の同意を得ます。この同意を得るプロセスもOIDCのフローに含まれています。
③ Google → アプリ
認証が成功すれば、Googleはアプリに認可コードを返却します。このとき、ユーザーの表示画面もアプリの画面に戻ります。
以下は、Googleからのレスポンスの例です。
HTTP/1.1 302 Found
Location: <アプリのリダイレクト先>
?code=<認可コード>
&state=TH25QRQHJJC16YY7AKNS
④ アプリ → Google
アプリはGoogleから受け取った認可コードをGoogleに送信して、IDトークン・アクセストークンとの交換をリクエストします。
具体的には、Googleの「トークンエンドポイント」に対して、「認可コード」を送信します。このアプリからGoogleへのリクエストを「トークンリクエスト」と呼びます。
以下はトークンリクエストの例です。
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
grant_type=authorization_code&code=<認可コード>
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
アプリの実装処理:「トークンリクエスト」の作成・送信
→ トークンエンドポイントに対して、認可コードを含めたHTTPリクエストを行う
⑤ Google → アプリ
Googleでは認可コードの検証を行い、検証が成功したらアプリに対してIDトークンとアクセストークンを返却します。
以下はレスポンスの例です。
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
}
IDトークンはJWT(JSON Web Token)形式であり、JSON形式のデータをBASE64URLエンコードしています。IDトークンにはGoogleが管理するユーザー属性が含まれており、デコードすることでアプリはこれらのユーザーデータを使用できます。
アクセストークンは、Googleに対して追加でユーザー情報をリクエストする場合に使用します(フロー⑦,⑧)。
⑥ アプリ
アプリはIDトークン(JWT)をデコードし、その内容について検証します。検証内容は以下のように複数ありますが、Pythonの場合はAuthlibなどのライブラリで検証用モジュールが用意されています。

出典: 3.1.3.7. ID Token Validation
Authlibでは、JWT実装のために以下のようなモジュールを提供しています。
-
decode(id_token, public_key):JWTのデコードを行う -
validate(payload, header):IDトークン(JWT)のペイロードを検証する
アプリの実装処理:「IDトークン」の検証
→ JWTは標準規格のため、Pythonのライブラリで用意されているモジュールを使用できる
まとめ
本記事で整理した内容により、AIに生成させたPythonコードをチェックできるくらいの理解にはなったかなと個人的には思います。ClientとUser Agentをひとまとめに「アプリ」と表現したり、IdP側の処理を割愛したり、詳しい方が読むとツッコミどころが多いかもしれませんが、明らかな誤りがあればご指摘いただけると幸いです。あと、Authorization Codeの訳は認可コードと認証コード、どちらが適切なのでしょうか…
さて、Pythonによる実装編の投稿に向けて頑張りたいと思います。
