OpenID Connect

OAuth 2.0 の上に構築された認証レイヤーで、ユーザーの身元情報を ID トークンとして提供する

認証ネットワーク

OpenID Connect とは

OpenID Connect (OIDC) は、OAuth 2.0 の上に構築された認証レイヤーである。OAuth 2.0 が「認可」(何にアクセスできるか) を扱うのに対し、OIDC は「認証」(誰であるか) を扱う。認証成功時に ID トークン (JWT) を発行し、ユーザーの身元情報をクライアントに提供する。Core 1.0 (final) は 2014 年 2 月に OpenID Foundation がまとめたもので、現在参照すべき版は誤記修正を取り込んだ errata set 2 (2023 年 12 月 15 日) である。実装側の利点は、IdP ごとに異なる独自のログイン API を書かずに、署名検証と数個のクレーム照合という同じ手順を使い回せる点にある。

OAuth 2.0 との違い

両者は競合する仕様ではない。OIDC は OAuth 2.0 のフローをそのまま使い、身元を伝えるための約束事 (ID トークンとクレーム名、UserInfo エンドポイント) を足したものである。違いは次の 4 点に集約される。

観点OAuth 2.0OpenID Connect
目的認可 (リソースへのアクセス許可)認証 (ユーザーの身元確認)
トークンアクセストークンID トークン + アクセストークン
ユーザー情報標準化されていないUserInfo エンドポイントで標準化
スコープread, write など任意openid, profile, email

OAuth 2.0 だけでは「このアクセストークンは誰のものか」が分からない。OIDC の ID トークンにユーザー情報が含まれる。

この差は形式にも現れる。ID トークンはクライアント自身が検証する前提で署名された JWT だが、アクセストークンは形式が規定されておらず、クライアントが中身を読む前提のものではない。アクセストークンを受け取れたことをログイン成功と読み替えると、別のクライアント向けに発行されたトークンでも通ってしまう。

ID トークン (JWT)

ID トークンは JWT なので、復号ではなく署名検証で真正性を確かめる。ペイロードは次のようなクレームの集合である。

{
  "iss": "https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxx",
  "sub": "user-123",
  "aud": "client-id",
  "exp": 1711900800,
  "iat": 1711897200,
  "nonce": "n-0S6_WzA2Mj",
  "email": "user@example.com",
  "name": "Alice",
  "email_verified": true
}
クレーム説明
iss発行者 (IdP の URL)
subユーザーの一意識別子
aud対象のクライアント ID
exp有効期限
iat発行時刻 (時計のずれを見込んだ許容幅を持たせて扱う)
nonce認可リクエストで送った値。同じ ID トークンの再利用を弾くために照合する
emailメールアドレス

検証で確かめるのは、JWKS の公開鍵による署名、iss が想定した IdP と一致すること、aud が自分のクライアント ID であること、exp が未来であること、nonce が自分の送った値であることの 5 点である。抜けやすいのは aud の照合で、ここを省くと他アプリ向けに発行された正しい署名の ID トークンをそのまま受け入れてしまう。

認証フロー (認可コード + PKCE)

認可コードフローに PKCE を組み合わせた場合、やり取りは次の順に進む。

1. クライアントが認可リクエスト (scope: openid profile email)
2. ユーザーが IdP でログイン
3. IdP が認可コードを返す
4. クライアントが認可コードをトークンエンドポイントに送信
5. IdP が ID トークン + アクセストークンを返す
6. クライアントが ID トークンを検証 (署名、exp、aud)
7. UserInfo エンドポイントで追加情報を取得 (オプション)

PKCE が効くのは 4 の交換時である。クライアントは 1 で乱数 (code_verifier) のハッシュを送っておき、4 で元の乱数を提示する。認可コードだけを盗んでも元の乱数を知らなければトークンに交換できないため、リダイレクト経路で漏れたコードが使えなくなる。公開クライアント (SPA・モバイルアプリ) では PKCE の使用が RFC 9700 (BCP 240・2025 年 1 月) で必須とされている。

Cognito での OIDC

Cognito User Pool は OIDC プロバイダーとして機能する。

// ホステッド UI のドメイン側
// 認可: https://<domain>/oauth2/authorize
// トークン: https://<domain>/oauth2/token
// UserInfo: https://<domain>/oauth2/userInfo

// ユーザープールの発行者ホスト側
// JWKS: https://cognito-idp.<Region>.amazonaws.com/<userPoolId>/.well-known/jwks.json

ホステッド UI のドメインと、トークンを発行するユーザープール自身のホストは別物である。JWKS は後者にあり、その URL は ID トークンの iss と同じホストになる。前者のドメインで鍵を探すと 404 になるため、検証コードでは iss を組み立て直して鍵を引く方が間違いが少ない。

OIDC Discovery

.well-known/openid-configuration エンドポイントで、IdP の設定情報 (認可エンドポイント、トークンエンドポイント、JWKS URI) を自動取得できる。クライアントは IdP の URL だけ知っていれば、残りの設定を自動的に取得する。

実装で決めておくことが 2 つある。1 つはこの設定と JWKS をキャッシュすること (リクエスト毎に取りに行くと IdP がそのまま自分の障害点になる)。もう 1 つは鍵の入れ替えに備えて、ID トークンのヘッダーの kid に合う鍵が手元に無いときだけ JWKS を取り直す形にすることである。有効期限を無視して永久にキャッシュすると、鍵が入れ替わった瞬間に全ユーザーの検証が落ちる。

SAML との比較

SAML 2.0 は XML でやり取りする先行世代の仕様である。選択の分かれ目は、扱うクライアントの種類と、既存の IdP がどちらを話せるかにある。

観点OIDCSAML 2.0
データ形式JSON / JWTXML
用途Web / モバイルエンタープライズ SSO
実装の複雑さ低い高い
モバイル対応適している不向き

新規に選ぶなら OIDC が扱いやすい。JSON と JWT で完結するためモバイルアプリや SPA 向けのライブラリが揃っており、鍵の取得から署名検証までを任せられる。逆に、社内の既存 IdP が SAML しか話せない場合や、連携先の SaaS 群が SAML 前提で組まれている場合は SAML を使う (両方を話せる IdP を挟んで変換する構成もある)。

実装に入る前に確認したいのは、使う言語の検証ライブラリが iss / aud / exp / nonce の照合と kid による鍵の引き当てまで面倒を見てくれるかどうかである。この部分を手書きすると、最初に抜けるのはほぼ aud の照合である。

この記事は役に立ちましたか?

関連用語

関連する記事