LASSIC Media らしくメディア

2026.10.06 らしくコラム

OpenID Connectの仕組み、OAuthとの違い

監修・編集責任者:牛尾 昭昌(株式会社LASSIC 執行役員)

外部アカウントで続行するボタンが2つ並んだWebサービスのサインイン画面を、斜めから接写した画面の写真。

この記事の結論

  • OpenID Connectは、OAuth 2.0の上に、誰がログインしたかを伝えるIDトークンを足した認証の層です。
  • IDトークンは署名・iss・aud・exp・nonceの順に検証し、利用者はissとsubの組で識別します。
  • アクセストークンでログイン扱いせず、認可コードフローとPKCEを使い、拒否される場合まで試験します。

※ 本記事は2026年10月時点の公式情報(省庁・公的機関、および製品やサービスを提供する事業者が公開している資料)に基づきます。

OpenID Connectは、OAuth 2.0の上に「誰がログインしたか」を受け渡す層を足した標準仕様です。外部のアカウントでログインするボタンや、社内のシングルサインオンの裏側で広く使われています。ところが実装の現場では、OAuthのアクセストークンを受け取れただけでログイン済みと扱ってしまう、IDトークンを受け取っても中身を確かめずに使ってしまう、といった誤りが起こりがちです。

本記事では、Webシステムや業務アプリの開発・運用に携わる方と、認証の仕組みへの投資を判断する方に向けて、OpenID Connectの仕組みをIDトークン・UserInfo・Discoveryの3つの部品に分けて整理します。検証手順のPythonコード、SAMLとの違い、つまずきやすい点、外部に委託するときに確かめたい点まで扱います。

OpenID Connectとは

仕様の本体であるOpenID Connect Core 1.0は、自らを「OAuth 2.0の上に載せたシンプルなアイデンティティ層」と説明しています。*1 認可サーバーが行った認証の結果をもとに、クライアントが利用者の身元を確かめ、氏名やメールアドレスといった基本的なプロフィールを相互運用できる形で受け取れるようにする仕様です。

OAuth 2.0は、あるアプリにAPIへのアクセスを許可する「認可」の仕組みです。アクセストークンは「このAPIをこの範囲で呼んでよい」という許可を表すだけで、誰がいつログインしたかは伝えません。OpenID Connectは、ここに「認証」の結果を運ぶ部品を加えます。OAuthの登場人物と認可コードフローは「OAuth入門」、認証と認可の区別は「認証と認可の違い」で解説しています。

用語も少し変わります。OpenID Connectでは、ログインを受け持つ認可サーバーをOpenIDプロバイダー(OP)、ログインの結果を受け取るアプリをリライングパーティー(RP)と呼びます。RPがOAuthの認可リクエストのscopeにopenidという値を含めると、それがOpenID Connectのリクエストになります。Core 1.0は、openidが無い場合の動きは「まったく定めない」としています。*1

仕組み:IDトークンとUserInfo

OpenID ConnectがOAuth 2.0に足すいちばん大きな部品が、IDトークンです。*1 IDトークンはJWT(署名付きのJSON形式のトークン)で表され、認証についての情報(クレーム)を持ちます。JWTの3つの部分の構造は「JWTとは」で扱っているので、ここではIDトークンに入る主なクレームを見ます。

IDトークンに入る主なクレーム(Core 1.0 第2節)
クレーム 意味 RPが確かめること
iss 発行者の識別子(httpsのURL)。必須 Discoveryで得たissuerと完全に一致するか
sub 発行者の中で利用者を表す識別子。255文字以内で、別の人に再び割り当てられない。必須 issと組にして利用者のキーにする
aud 宛先。RPのclient_idを含まなければならない。必須 自分のclient_idを含むか
exp 期限。この時刻以降は受け付けない。必須 現在の時刻が期限より前か
iat 発行された時刻。必須 発行から時間がたちすぎていないか
nonce 認証リクエストで送った値がそのまま入る 送った値と同じか

expとiatはJWTの仕様(RFC 7519)と同じく、1970年1月1日0時(UTC)からの秒数で表します。*3 nonceは必須のクレームではありませんが、認証リクエストでnonceを送った場合、OPはそれをIDトークンに入れなければならず、RPは値が同じかを確かめなければなりません。

もう1つの部品がUserInfoエンドポイントです。RPはOpenID Connectのリクエストで得たアクセストークンを付けてここを呼び、利用者の属性を受け取ります。scopeにprofile・email・address・phoneを加えると、それぞれに対応する属性を求められます。UserInfoの応答には常にsubが入り、RPはそれがIDトークンのsubと完全に一致することを確かめます。一致しなければ、応答の値を使ってはいけません。*1

認可コードフローでの認証リクエストは、例えば次の形になります(Core 1.0の例に、nonceとPKCEの値を加えたもの)。

GET /authorize?
  response_type=code
  &scope=openid%20profile%20email
  &client_id=s6BhdRkqt3
  &state=af0ifjsldkj
  &nonce=n-0S6_WzA2Mj
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com

利用者がOPでログインと同意を済ませると、RPに認可コードが戻ります。RPはそれをトークンエンドポイントで、IDトークンとアクセストークンに引き換えます。ここまでの往復はOAuthの認可コードフローと同じで、違いは応答にIDトークンが入る点にあります。

Discoveryで設定を読む

RPは、OPのどのURLに何を送るかを知る必要があります。OpenID Connect Discovery 1.0は、発行者(issuer)のURLの末尾に /.well-known/openid-configuration を付けた場所に、設定を記したJSON文書を置くよう定めています。*2 issuer・authorization_endpoint・jwks_uri・response_types_supported・subject_types_supported・id_token_signing_alg_values_supportedは必須の項目です。

公開されているGoogleのDiscovery文書を2026年10月1日にcurlで取得すると、次の項目が返りました(一部を抜き出したもの)。*7

$ curl -s https://accounts.google.com/.well-known/openid-configuration
{
 "issuer": "https://accounts.google.com",
 "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
 "token_endpoint": "https://oauth2.googleapis.com/token",
 "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
 "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
 "id_token_signing_alg_values_supported": ["RS256"],
 "scopes_supported": ["openid", "email", "profile"],
 "code_challenge_methods_supported": ["plain", "S256"],
 ...
}

jwks_uriは、OPがIDトークンの署名に使う公開鍵の一覧(JWKセット)の場所です。JWKセットはRFC 7517が定める形式で、鍵ごとにkid(鍵の識別子)を持ちます。*4 Core 1.0は、OPが鍵を入れ替えるときは新しい鍵をJWKセットに足してkidで知らせ、RPは見慣れないkidを見たらjwks_uriを取り直す、という手順を示しています。*1 鍵をコードに直接書き込むと、入れ替えの日にログインが止まります。

Discovery 1.0は、返ってきたissuerが取得に使ったURLと同じでなければならないとも定めています。*2 設定ファイルにはissuerのURLだけを書き、エンドポイントは起動時にDiscoveryから読むようにすると、OPの切り替えが楽になります。

IDトークンの検証手順

Core 1.0の3.1.3.7節は、RPがIDトークンをどう検証するかを順に定めています。*1 暗号化の扱いなどを除くと、要点は下の図の6つです。

IDトークンの検証手順を上から順に示した図。トークンエンドポイントからIDトークンを受け取った後、(1)ヘッダーのkidでjwks_uriの鍵セットから公開鍵を選び、algを固定して署名を検証、(2)issがDiscoveryのissuerと完全に一致するか、(3)audが自分のclient_idを含み信頼しない宛先が混じっていないか、(4)expとiatで期限前か・発行が古すぎないかを自分の時計(ずれは数分まで)と照らす、(5)nonceがセッションに保存した、認証リクエストで送った値と同じか、(6)issとsubの組で利用者を特定し、メールアドレスは識別子に使わない。(1)から(5)のどれか1つでも合わなければ、そのトークンでログインさせない。

図の(2)と(3)は、文字列の一致で確かめます。Core 1.0は、audに自分のclient_idが無い場合だけでなく、信頼していない別の宛先が含まれている場合も拒否するよう求めています。(4)の時計のずれについては、通常は数分までの猶予を見込んでよいとされています。

PythonのPyJWTで書くと次のようになります。自作のRSA鍵とJWTで、正しいトークンが通り、aud・iss・nonceの違い、期限切れ、別の鍵の署名、HS256への差し替えがすべて拒否されることを確かめました(PyJWT 2.15.1)。

import jwt  # PyJWT

def verify_id_token(id_token, jwks, issuer, client_id, nonce):
    # ヘッダーの kid で、Discovery の jwks_uri から得た鍵を選ぶ
    kid = jwt.get_unverified_header(id_token)["kid"]
    key = jwt.PyJWKSet.from_dict(jwks)[kid].key
    claims = jwt.decode(
        id_token, key,
        algorithms=["RS256"],           # 受け付ける署名方式を固定する
        audience=client_id,             # aud に自分の client_id があるか
        issuer=issuer,                  # iss が Discovery の issuer と一致するか
        options={"require": ["iss", "sub", "aud", "exp", "iat"]},
        leeway=60,                      # 時刻のずれを60秒まで許す
    )
    if claims.get("nonce") != nonce:    # 認証リクエストで送った値か
        raise jwt.InvalidTokenError("nonce mismatch")
    return claims["iss"], claims["sub"]  # 利用者を識別するのはこの組

algorithmsで受け付ける署名方式を固定しているのは、トークンのヘッダーに書かれたalgをそのまま信じないためです。なおPyJWTは、audが配列で自分以外の宛先が並んでいても、自分が含まれていれば通します。複数の宛先を想定しない場合は、配列の中身まで確かめる処理を足します。

SAMLとの違い

企業向けのシングルサインオンでは、SAMLもよく使われます。役割の比較やSAMLの仕組みそのものは「SAMLとは」で整理しているので、ここでは実装する側から見た違いに絞ります。

実装する側から見たOpenID ConnectとSAML 2.0の違い
観点 OpenID Connect SAML 2.0
認証の結果を運ぶもの IDトークン(JWT) アサーション(XML)
署名の方式 JSONの署名(JWS) XML署名
設定の受け渡し Discovery文書(JSON)をURLから取得する メタデータ(XML)を事前に交換する
結果の受け取り方 認可コードをサーバー間の通信で引き換えるのが基本 ブラウザ経由で送られてくる形が多い
APIの呼び出し 同じ流れでアクセストークンも得られる OAuthなどを別に組み合わせる

どちらを選ぶかは、つなぐ相手の対応状況でほぼ決まります。新しく作るアプリはOpenID Connect、SAMLにしか対応しない既存のSaaSはSAMLでつなぎ、認証基盤の側で両方を受け持つ構成もとれます。

使いどころ

OpenID Connectが向くのは、次のような場面です。

  • 社員向けの業務システムに、Microsoft Entra IDやKeycloakなどの認証基盤でシングルサインオンを入れる
  • 法人顧客向けのWebサービスに、取引先がふだん使うIDでログインできる入口を設ける
  • ブラウザだけで動くアプリ(SPA)やスマートフォンアプリで、ログインとAPIの呼び出しを1つの流れでまかなう
  • 複数のサービスに散らばった利用者のIDを、1か所で管理する

いずれも、アプリごとにパスワードを持たずに済み、パスワードの保管や多要素認証の実装をOPに任せられる点が利点です。その一方で、OPが止まるとすべてのアプリにログインできなくなるため、OPの可用性と障害時の業務の続け方は別に決めておきます。

つまずきやすい点

最も多いのは、OAuthのアクセストークンを受け取れたことをもって、ログイン済みと扱う誤りです。アクセストークンはAPIを呼ぶための許可で、宛先はリソースサーバーです。別のアプリ向けに発行されたアクセストークンでもAPIを呼べてしまえば、「ログインできた」ように見えます。ログインの判断には、宛先(aud)が自分であることを確かめたIDトークンを使います。

次に多いのが、IDトークンを受け取りながら、署名の検証だけで終えてaudやnonceを見ない実装です。audを見ないと、同じOPを使う別のアプリ向けのIDトークンが自分のアプリで通ります。nonceを見ないと、盗んだトークンを差し込む攻撃を防げません。RFC 9700は、nonceが偽のリクエストを送らせる攻撃(CSRF)への備えになるとし、値は取引ごとに作り、ログインを始めたブラウザに結び付けるよう求めています。*5

メールアドレスを利用者のキーにするのも危うい設計です。Core 1.0は、利用者を安定して識別できるのはissとsubの組だけで、emailなどを一意の識別子に使ってはならないとしています。*1 メールアドレスは変わることがあり、発行者によっては時期を変えて別の人に割り当てられることもあるからです。

古い解説にある、ブラウザに直接トークンを返すインプリシットフローも避けます。RFC 9700は、認可レスポンスでアクセストークンを返す方式は漏えいや再利用に弱いとして、使うべきではないとしています。*5 代わりに認可コードフローを使い、秘密の情報を持てないSPAやスマートフォンアプリではPKCEの使用が必須です。PKCEの方式には、RFC 7636が定める、code_verifierのSHA-256ハッシュをcode_challengeとして送るS256を選びます。*6

外部に委託するときに確認したい点

OpenID Connectの組み込みを外部に頼むときは、設計書と受け入れ試験で次の点を確かめます。

  • ログインの判断にIDトークンを使い、3.1.3.7節の検証を、どのライブラリのどの設定で満たしているか
  • 利用者テーブルのキーをissとsubの組にしているか(メールアドレスにしていないか)
  • 認可コードフローとPKCE(S256)を使い、stateとnonceを取引ごとに作っているか
  • エンドポイントと公開鍵をDiscoveryとjwks_uriから読み、鍵の入れ替えで止まらないか
  • ログアウトやアカウントの停止のとき、アプリ側のセッションをどう終わらせるか

受け入れでは、正常にログインできることだけでなく、拒否されるべきトークンが本当に拒否されるかを試験の項目に入れます。上のコードで試した拒否の例に、知らないkidを持つトークンも加えておくと確実です。KeycloakなどでOPの側も構築する場合は「KeycloakでSSO認証基盤を外注構築」、委託の範囲の切り分けは「認証基盤・IDaaS連携開発の外注」も参考になります。

まとめ:OpenID Connectで確かめる3点

OpenID Connectを組み込むうえで、確かめておきたい点は3つに整理できます。第一に、ログインの判断にはアクセストークンではなく、検証したIDトークンを使うこと。第二に、署名・iss・aud・exp・nonceの検証を省かず、拒否されるべきトークンでも試験すること。第三に、利用者をissとsubの組で識別し、エンドポイントと鍵をDiscoveryから読むことです。この3点を押さえておけば、「別のアプリ向けのトークンでログインできてしまった」という事態を避けやすくなります。認証の設計や既存の仕組みの見直しに迷いがあれば、外部の手を借りるのも一つの選択肢です。

LASSICに相談するメリット

LASSICは、システム開発と保守運用を元請(プライムベンダー)として受託しています。OpenID Connectの組み込みでは、Microsoft Entra IDやKeycloakなどのOP、PyJWT・Spring Security・Auth.jsなどのRP側のライブラリ、セッションを保持するRedisを組み合わせて扱います。設計では、認可コードフローとPKCEの使い方、stateとnonceの作り方と保存先、利用者のキー(issとsub)、鍵の入れ替えとOPが止まったときの扱いを、業務の使われ方と照らして決めます。運用では、aud違いや期限切れなど拒否されるべきトークンの自動テストをCI/CDに組み込み、OPのクライアント設定はTerraformなどのIaCで管理し、検証エラーの急増とjwks_uriの取得失敗を監視の項目に入れます。

よくある質問

IDトークンをAPIの呼び出しに使ってもよいですか

勧められません。IDトークンの宛先(aud)はRPのclient_idで、RPが認証の結果を受け取るためのものです。APIを呼ぶときは、そのAPI向けに発行されたアクセストークンを使います。2つの役割を分けておくと、宛先の検証も崩れません。

IDトークンの期限が切れたら、利用者を再ログインさせる必要がありますか

そうとは限りません。Core 1.0は、IDトークンの期限はRPとOPの間のログイン状態の長さとは関係がないと注記しています。IDトークンはログインの時点で検証し、その後はRP自身のセッションで利用者を管理するのが一般的です。

UserInfoを呼ばずに、IDトークンだけで属性を得られますか

OPと設定しだいです。Core 1.0では、profileやemailのscopeで求めた属性は、アクセストークンが発行される場合はUserInfoから返すとしています。ただしIDトークンにも入れて返すOPもあるため、使うOPのDiscovery文書のclaims_supportedと、実際の応答を確かめます。

OpenID Connectを使ったログインの設計のご相談

元請(プライムベンダー)として、認証の設計と実装から、システムの保守・運用までご提案します。

Remoguとリラシクなら、認証基盤の構築やログイン機能の実装に加わるITエンジニアも探せます。

Remoguは、リモート前提で全国から即戦力のITプロ人材を調達するサービスです。リラシクは、扱う求人がすべてリモートワークのITエンジニア専門転職エージェントです。どちらもLASSICが運営しています。

無料相談はこちら

出典

  1. *1 参考:OpenID Foundation「OpenID Connect Core 1.0 incorporating errata set 2」(2023年12月15日)(https://openid.net/specs/openid-connect-core-1_0.html)。出典:概要(OAuth 2.0の上のアイデンティティ層)・2節(IDトークンのクレーム)・3.1.2.1節(scopeのopenid、認証リクエストの例)・3.1.3.7節(IDトークンの検証)・5.3節(UserInfo)・5.4節(scopeで求める属性)・5.7節(issとsubの組)・10.1.1節(署名鍵の入れ替え)を参照(2026年10月確認)
  2. *2 参考:OpenID Foundation「OpenID Connect Discovery 1.0 incorporating errata set 2」(2023年12月15日)(https://openid.net/specs/openid-connect-discovery-1_0.html)。出典:3節(OPのメタデータと必須の項目)・4節(/.well-known/openid-configuration の取得とissuerの一致)を参照(2026年10月確認)
  3. *3 参考:IETF「RFC 7519 JSON Web Token (JWT)」(https://www.rfc-editor.org/rfc/rfc7519)。出典:2節(NumericDate)・4.1.4節(exp)を参照(2026年10月確認)
  4. *4 参考:IETF「RFC 7517 JSON Web Key (JWK)」(https://www.rfc-editor.org/rfc/rfc7517)。出典:4.5節(kid)・5節(JWKセット)を参照(2026年10月確認)
  5. *5 参考:IETF「RFC 9700 Best Current Practice for OAuth 2.0 Security」(2025年1月)(https://www.rfc-editor.org/rfc/rfc9700)。出典:2.1節(OpenID Connectのnonceによる備え)・2.1.1節(PKCE、nonceを取引ごとに作る)・2.1.2節(インプリシットグラントを使わない)を参照(2026年10月確認)
  6. *6 参考:IETF「RFC 7636 Proof Key for Code Exchange by OAuth Public Clients」(https://www.rfc-editor.org/rfc/rfc7636)。出典:4.2節(S256の計算式)・付録B(code_verifierとcode_challengeの例)を参照(2026年10月確認)
  7. *7 参考:Google「OpenID Connect Discovery 文書(accounts.google.com/.well-known/openid-configuration)」(https://accounts.google.com/.well-known/openid-configuration)。出典:2026年10月1日にcurlで取得した実際の項目(issuer・各エンドポイント・jwks_uri・署名方式・scope・PKCEの方式)を参照(2026年10月確認)




View