OIDC(OpenID Connect、読み方はオープンアイディー・コネクト)は、OAuth 2.0の上に「このユーザーは誰か」を確かめる仕組みを足した認証の仕様です。OAuth 2.0だけでは、アプリは「APIを呼んでよい権限」を受け取れても、ログインした本人が誰かを確実には知れません。OIDCはそこにIDトークンという署名付きの本人確認書を加えました。本記事では、IDトークンに入る必須項目と、受け取ったアプリが仕様上どの順で何を検証しなければならないかを、OpenID Connect Core 1.0の原文にもとづいて整理します。aud の意味と、OAuth 2.0・SAMLとの違いも扱います。
まとめ:OIDCの要点とIDトークン検証で外せない項目
- OIDCはOAuth 2.0を拡張した認証レイヤーです。認可リクエストの
scopeにopenidを入れると、トークンレスポンスにIDトークンが加わります。 - IDトークンはJWTで、
iss(発行者)・sub(ユーザー識別子)・aud(宛先のclient_id)・exp(有効期限)・iat(発行時刻)の5つが必須です。 - 受け取ったアプリは、
issの完全一致、audに自分のclient_idが含まれること、署名、exp、送ったnonceとの一致を検証します(Core 3.1.3.7)。audを見ないと、別アプリ向けに発行されたトークンでログインを通してしまいます。 - ユーザーを識別するキーは
issとsubの組です。メールアドレスは発行者側で再利用されることがあり、キーにしてはいけません(Core 5.7)。 - フローは認可コードフロー(
response_type=code)+PKCEが既定です。認可レスポンスでアクセストークンを返す型は、RFC 9700が非推奨(SHOULD NOT)としています。
OIDCの定義と仕様の位置づけ
OAuth 2.0に足されたIDトークンとopenidスコープ
Coreの冒頭は、OIDCを「OAuth 2.0プロトコルの上に載るシンプルなIDレイヤー」と定義しています。最もよく使う認可コードフローで見ると、やり取りの形はOAuth 2.0の認可リクエストとトークンリクエストのままで、違いは2点です。認可リクエストの scope に openid を含めること、そしてトークンエンドポイントがアクセストークンに加えてIDトークンを返すことです(トークンエンドポイントを使わないインプリシットフローでは、IDトークンは認可レスポンスで返ります)。Coreは「OAuth 2.0を認証に使えるようにする主な拡張がIDトークンというデータ構造である」と書いています。
OAuth 2.0そのものの仕組みとロールはOAuth 2.0とは?仕組み・認可フローと認証との違い、OAuth 2.1の変更点をわかりやすく解説で扱っています。
OP・RP・エンドユーザーの3者の関係
OIDCの登場人物は3者です。ログインする人がエンドユーザー、ユーザーを認証してIDトークンを発行するのがOpenIDプロバイダー(OP)、IDトークンを受け取ってログインを成立させるアプリがリライングパーティー(RP)です。「Googleでログイン」なら、Googleアカウントの認証基盤がOP、ログインボタンを置いたWebサービスがRPになります。OAuth 2.0の用語に当てはめると、OPは認可サーバー、RPはクライアントです。
OPには、Google・Microsoft Entra ID・Apple・Auth0・Amazon Cognitoなどのクラウドサービスのほか、Keycloakのように自社で立てるソフトウェアもあります。Keycloakのトークンエンドポイントは /realms/{realm-name}/protocol/openid-connect/token という形で、パスに openid-connect が入ります。
仕様の版とISO標準化の時期
| 時期 | 出来事 |
|---|---|
| 2014-02-26 | OpenID Connect 1.0 Final 公開 |
| 2014-11 | Core errata set 1 |
| 2023-12-15 | Core errata set 2(現行版) |
| 2024-10-07 | 9仕様がISO/IEC標準化と発表 |
現行のCoreは「incorporating errata set 2」の版です。ISO/IEC 26131:2024がCore、26132:2024がDiscovery、26133:2024がDynamic Client Registrationに当たります。実装で参照するのは、openid.netで無償公開されている原文で足ります。
OAuth 2.0とOIDCの違い:認可と認証
| 観点 | OAuth 2.0 | OIDC |
|---|---|---|
| 目的 | 認可(APIを呼ぶ権限の委譲) | 認証(ログインした本人の確認) |
| 主な成果物 | アクセストークン | IDトークン(+アクセストークン) |
| トークンの宛先 | リソースサーバー(API) | クライアント(RP)自身 |
| トークンの形式 | 規定なし | JWT(原則署名付き) |
| 仕様 | RFC 6749(IETF) | Core 1.0(OpenID Foundation) |
違いの核心は「トークンの宛先」です。アクセストークンはAPIに見せるためのもので、クライアントが中身を読んで解釈することをOAuth 2.0は想定していません。IDトークンはクライアント自身に宛てたもので、aud にクライアントのclient_idが入ります。
アクセストークンだけでログインを判定する危険
OAuth 2.0だけでログイン機能を作ると、「アクセストークンが取れた=その人がログインした」とみなしがちです。しかしOAuth 2.0単独では、クライアントがアクセストークンを見て「自分に向けたログイン結果か」を確かめる手順が標準化されていません(JWT形式のアクセストークンを定めたRFC 9068には client_id がありますが、これはAPI側が読むための項目です)。攻撃者が自分の運営する別アプリで被害者のアクセストークンを集め、それを標的アプリに差し出すと、トークンの宛先を確かめない標的アプリは被害者としてログインさせてしまいます。IDトークンは aud で宛先のアプリを示し、nonce でその認証リクエストに結び付けるため、この差し替えを検知できます。OAuth 2.0でログインを組みたくなったら、それはOIDCを使う場面です。
IDトークンとアクセストークンの違い
| 項目 | IDトークン | アクセストークン |
|---|---|---|
| 誰が読むか | クライアント(RP) | API(リソースサーバー) |
| audに入る値 | RPのclient_id | APIの識別子(JWTの場合) |
| 形式 | 署名付きJWT | JWTまたは不透明な文字列 |
| API呼び出しに使うか | 使わない | 使う |
ログイン用にRPへ発行されたIDトークンを、そのままAPIへのBearerトークンとして流用する実装は誤りです。そのIDトークンの aud はRPのclient_idなので、宛先を検証するAPIなら拒否します。例外は、Google Cloud Runのサービス間認証のように、aud に呼び出し先のサービスを指定したIDトークンを発行し、それをBearerで送る方式です。この場合もAPIは aud が自分であることを検証しており、ログイン用トークンの流用とは別物です。
IDトークンに入る必須クレームと条件付きクレーム
Coreの2章が定めるIDトークンの中身は次のとおりです。下のJSONはCore 2章に載っている例です。
{
"iss": "https://server.example.com",
"sub": "24400320",
"aud": "s6BhdRkqt3",
"nonce": "n-0S6_WzA2Mj",
"exp": 1311281970,
"iat": 1311280970,
"auth_time": 1311280969,
"acr": "urn:mace:incommon:iap:silver"
}
| クレーム | 要否 | 意味 |
|---|---|---|
| iss | 必須 | 発行者。httpsのURL |
| sub | 必須 | 発行者内で一意・再割り当てなしのユーザーID(ASCII 255文字以内) |
| aud | 必須 | 宛先。RPのclient_idを含む |
| exp | 必須 | 有効期限(UNIX秒) |
| iat | 必須 | 発行時刻(UNIX秒) |
| nonce | リクエストに含めたら必須 | リクエストとの紐付け・リプレイ対策 |
| auth_time | max_age指定時・Essential要求時は必須 | ユーザーが認証した時刻 |
| acr / amr | 任意 | 認証の強度・使った認証手段 |
| azp | 任意 | トークンを受け取る当事者のclient_id |
exp はIDトークンの受け入れ期限で、Coreは「RPとOPの間のログインセッションの長さとは無関係」と明記しています。IDトークンが切れたからといってユーザーを即ログアウトさせる必要はなく、アプリのセッションは別に管理します。JWTのヘッダー・署名の構造そのものはJWTとは?構造・署名検証の仕組みとセッション・OAuth/OIDCとの違いを実装視点で解説で扱っています。
IDトークンの検証手順(Core 3.1.3.7)
仕様が定める検証項目と順序
認可コードフローでIDトークンを受け取ったRPは、Core 3.1.3.7に従って次の順に検証します。
- 暗号化されていれば復号する(登録時に暗号化を取り決めたのに平文なら拒否してよい)
- OPのIssuer Identifier(通常はDiscoveryで取得)と
issが完全一致すること audに自分のclient_idが含まれること。信頼していない宛先が混ざっていたら拒否するazpがある場合は、自分のclient_idと一致するかを確かめる- OPが公開する鍵で署名を検証する。
algの既定はRS256 - 現在時刻が
expより前であること - 必要なら
iatで古すぎるトークンを拒否する(許容幅はRPが決める) - 認証リクエストで
nonceを送ったなら、同じ値が入っていること acrやauth_timeを要求したなら、その値が要件を満たすこと
Coreは、トークンエンドポイントからTLSで直接受け取ったIDトークンに限り、署名検証の代わりにTLSのサーバー検証で発行者を確かめてもよいとしています。ただしこれは「省略してよい」という許可であって、ライブラリで署名を検証するほうが後からフローを変えたときにも安全です。
audの検証でよくある間違い
aud は1つなら文字列、複数なら配列で入ります。文字列を前提に payload.aud === clientId と書くと、配列で届いたトークンをすべて拒否します。逆に「どれかが一致すればよい」とだけ書くと、Coreが求める「信頼していない宛先が混ざっていたら拒否」を満たしません。
もう1つの典型は、比較する値の取り違えです。IDトークンの aud と比べるのはOPに登録したclient_idで、APIの識別子やアプリのURLではありません。複数のOPに対応するアプリでは、iss ごとにclient_idが違うため、発行者とclient_idの組で照合します。
Node.jsとjoseによる検証コード
次のコードは、認可コードフローでトークンエンドポイントから受け取った署名付き(暗号化なし)のIDトークンを、Discoveryで取得した鍵と発行者を使って検証します。署名・iss・aud・exp と必須クレームの有無はjoseの jwtVerify がまとめて確かめ、Coreが追加で求める sub の形式・宛先の混在・azp・nonce を後段で見ています。acr や auth_time を要求した場合の確認は含めていません。nonce は呼び出し側で認証リクエストごとに生成してセッションに保存し、検証が済んだら削除して、同じ値とトークンの再利用を防ぎます。
// verify-id-token.mjs(Node.js 20以上・jose 6系)
import { createRemoteJWKSet, jwtVerify } from 'jose';
const ISSUER = process.env.OIDC_ISSUER; // 例: https://accounts.google.com
const CLIENT_ID = process.env.OIDC_CLIENT_ID; // OPに登録したclient_id
const TRUSTED_AUDIENCES = [CLIENT_ID]; // audに入っていてよい値
// 1. Discoveryでjwks_uriとissuerを取る(URLを手で書かない)
// URLを組み立てるときだけ終端の / を除く(issとの比較にはISSUERをそのまま使う)
const conf = await (await fetch(`${ISSUER.replace(/\/$/, '')}/.well-known/openid-configuration`)).json();
if (conf.issuer !== ISSUER) throw new Error('issuer mismatch in discovery');
const JWKS = createRemoteJWKSet(new URL(conf.jwks_uri));
export async function verifyIdToken(idToken, expectedNonce) {
// 2. 署名・iss・aud・exp をまとめて検証(algは登録時の既定RS256に固定)
const { payload } = await jwtVerify(idToken, JWKS, {
issuer: ISSUER,
audience: CLIENT_ID,
algorithms: ['RS256'],
requiredClaims: ['iss', 'sub', 'aud', 'exp', 'iat'], // 指定しないと欠落を通す
clockTolerance: 60, // 時計のずれを60秒まで許容
});
if (typeof payload.sub !== 'string' || !/^[\x20-\x7e]{1,255}$/.test(payload.sub)) {
throw new Error('invalid sub');
}
// 3. audに信頼していない値が混ざっていたら拒否。azpがあれば自分のclient_idか
if ([].concat(payload.aud).some((a) => !TRUSTED_AUDIENCES.includes(a))) {
throw new Error('untrusted audience');
}
if (payload.azp !== undefined && payload.azp !== CLIENT_ID) throw new Error('azp mismatch');
// 4. 認証リクエストで送ったnonceと一致するか
if (payload.nonce !== expectedNonce) throw new Error('nonce mismatch');
return { sub: payload.sub, iss: payload.iss }; // ユーザーの識別は iss+sub の組で行う
}
このコードに不正なトークンを渡すと、次のように止まります(jose 6.2.12・Node.js 26.5.0で実行)。
| トークンの状態 | 結果 |
|---|---|
| aud が別のclient_id | ERR_JWT_CLAIM_VALIDATION_FAILED(aud) |
| iss が別の発行者 | ERR_JWT_CLAIM_VALIDATION_FAILED(iss) |
| aud に信頼外の値が混在 | untrusted audience |
| azp が別のclient_id | azp mismatch |
| nonce が不一致 | nonce mismatch |
| exp を60秒超過 | ERR_JWT_EXPIRED |
| exp・iat・sub が欠落 | ERR_JWT_CLAIM_VALIDATION_FAILED(missing) |
algorithms を指定しないと、トークン側のヘッダーが示すアルゴリズムをそのまま受け入れる余地が残ります。ここではCoreの既定であるRS256に固定しました。クライアント登録時に別のアルゴリズムを取り決めた場合は、OPの対応一覧ではなく登録した値に合わせます。requiredClaims を省くと、joseは exp などが欠けたトークンも通すので、必須の5項目は明示します。createRemoteJWKSet は未知の kid が来たときに鍵セットを取り直すため、OP側の鍵ローテーションにも追従します。
認証フローの種類とresponse_typeの対応
OIDCのフローは、認可リクエストの response_type の値で決まります(Core 3章)。
| response_type | フロー | アクセストークンの受け取り口 |
|---|---|---|
| code | 認可コードフロー | トークンエンドポイント |
| id_token | インプリシットフロー | 発行しない |
| id_token token | インプリシットフロー | 認可レスポンス |
| code id_token | ハイブリッドフロー | トークンエンドポイント |
| code token | ハイブリッドフロー | 認可レスポンス |
| code id_token token | ハイブリッドフロー | 認可レスポンス |
OAuth 2.0の response_type=token はIDトークンを返さないため、OIDCでは使いません(Core 3章の注記)。
認可コードフロー+PKCEが既定になった理由
2025年1月に出たOAuth 2.0のセキュリティ指針RFC 9700は、認可レスポンスでアクセストークンを返す型(表の「認可レスポンス」の3行)は漏えいと再利用に弱いとして、トークン注入と漏えい経路への対策が取れている場合を除き使わないよう求めています(2.1.2のSHOULD NOT)。代わりに挙げているのが code と、アクセストークンをトークンエンドポイントで返す code id_token です。さらに公開クライアント(SPAやスマホアプリ)ではPKCEが必須、機密クライアントでも推奨とされました(2.1.1)。
認可リクエストは次のような形になります。Core 3.1.2.1の例に、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
RFC 9700は、OIDCの nonce がCSRF対策にもなると述べています。ただしPKCEと nonce のどちらも、取引ごとに新しい値を作り、そのブラウザのセッションに結び付けて保存しなければ意味がありません。トークン交換までの具体的な実装は認可コードフローとは?認可リクエストからトークン交換までの実装手順と検証設計を解説、code_verifier の作り方はPKCEとは?認可コード横取り攻撃を防ぐcode_verifierの実装と検証設計を解説にまとめています。
インプリシットフロー・ハイブリッドフローが残る場面
response_type=id_token のインプリシットフローはアクセストークンを発行しないため、RFC 9700が非推奨とする「認可レスポンスでアクセストークンを返す型」には当たりません。それでもIDトークンがURLフラグメントでブラウザに渡るので、新規に採用する理由はほとんどありません。ハイブリッドフローの code id_token は、認可レスポンスの段階でIDトークンを受け取り、c_hash で認可コードの差し替えを検知したい場合に使われます。金融APIのように要件が厳しい領域以外では、code だけで足ります。
スコープとUserInfoエンドポイントで取れる情報
openid 以外に、Core 5.4は4つのスコープを定めています。
| スコープ | 返るクレーム |
|---|---|
| profile | name・given_name・family_name・picture・locale など14項目 |
| email・email_verified | |
| address | address |
| phone | phone_number・phone_number_verified |
アクセストークンを発行するフローでは、これらの属性はアクセストークンを使ってUserInfoエンドポイントから取得するのが基本です(Core 5.4)。UserInfoの応答に入る sub は、IDトークンの sub と完全一致することを確かめてから使います(Core 5.3.2)。一致を見ないと、別ユーザーの属性を取り違えるおそれがあります。IDトークンにも属性を入れるかどうかはOP次第で、Googleは claims_supported に email や name を挙げています。どのスコープに対応しているかは、次に説明するDiscoveryの scopes_supported で確認できます。Googleは openid・email・profile の3つだけを挙げています(2026年9月27日取得)。
Discoveryとopenid-configurationで分かること
OIDC Discovery 1.0に対応したOPは、発行者URLの末尾に /.well-known/openid-configuration を付けた場所で設定をJSONで公開します。発行者URLが / で終わる場合は、その / を除いてから付け足します。RPはここから各エンドポイントのURLと公開鍵の場所を取得できるので、URLをコードに書き込む必要がありません。Googleの設定は次のコマンドで取れます。
curl -s https://accounts.google.com/.well-known/openid-configuration
2026年9月27日に取得した結果のうち、主な項目は次のとおりです。
{
"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",
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"],
"code_challenge_methods_supported": ["plain", "S256"],
"authorization_response_iss_parameter_supported": true
}
Discovery 1.0で必須の項目は、issuer・authorization_endpoint・jwks_uri・response_types_supported・subject_types_supported・id_token_signing_alg_values_supported の6つです。token_endpoint はインプリシットフローだけのOPでなければ必須、userinfo_endpoint は推奨です。issuer の値は、IDトークンの iss と完全一致で比べる相手になります。Googleの例では末尾にスラッシュが付いていないので、https://accounts.google.com/ と書いた設定では一致しません。
OIDCとSAMLの違いと選び方
| 観点 | OIDC | SAML 2.0 |
|---|---|---|
| 策定 | OpenID Foundation(2014年) | OASIS(2005年) |
| 本人確認の形式 | IDトークン(JWT) | アサーション(XML) |
| API認可 | OAuth 2.0と一体 | 別途OAuth等が必要 |
| 主なログイン経路 | ブラウザ・ネイティブアプリ | ブラウザ(ECPプロファイルもある) |
| 主な利用先 | ソーシャルログイン・SaaS・API | 社内SSO・既存の業務SaaS |
新しく作るアプリは、OIDCを第一候補にします。1回の認可コードフローでIDトークンとAPI用のアクセストークンを同時に受け取れること、スマホアプリ向けにPKCE付きの認可コードフローがRFC 8252として標準化されていることが理由です。SAMLを選ぶのは、つなぎ先の社内IdPや業務SaaSがSAMLしか受け付けない場合です。方式を決める前に、つなぐ予定のIdPと業務SaaSそれぞれの管理画面やドキュメントで、OIDCのアプリ登録とSAMLのどちらに対応しているかを確かめます。SAML側のフローと署名検証の勘所はSAMLとは?認証フロー・IdP/SPの仕組みとOAuth・OIDCとの使い分けを実装視点で解説で扱っています。
GitHub ActionsのOIDC連携:人がいない認証への応用
OIDCはログイン画面のない場面でも使われています。代表例がGitHub Actionsからクラウドへの認証です。ワークフローに id-token: write の権限を与えると、GitHubのOP(https://token.actions.githubusercontent.com)がジョブごとに短命なIDトークンを発行します。AWS・Google Cloud・Azureなどはこのトークンを検証し、条件に合えば一時的な認証情報を返します。クラウドのアクセスキーをSecretsに保存しなくて済むのが利点です。
permissions:
id-token: write # OIDCトークンの取得に必要
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy
aws-region: ap-northeast-1
# audience の既定値は sts.amazonaws.com
クラウド側の信頼条件で見るのは aud と sub です。GitHubのIDトークンの aud は、既定ではリポジトリ所有者のURL(https://github.com/my-org など)で、AWSのアクションは sts.amazonaws.com を指定してトークンを取得します。sub は repo:octo-org/octo-repo:ref:refs/heads/main のようにリポジトリとブランチ・環境を連結した値です。
2026年7月15日以降に作成されたリポジトリでは、sub の既定形式が repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main のように所有者IDとリポジトリIDを含む形へ変わりました。組織名を手放した後に別人が同じ名前を取ると、旧形式では同じ sub が作れてしまうためです。それより前に作成されたリポジトリは、組織・リポジトリ単位でオプトインするか、2026年7月15日以降に改名・移管されない限り旧形式のままです。GitHub Enterprise Serverはこの変更の対象外です(GitHub DocsのOIDCリファレンス)。信頼ポリシーを書き写すときは、どちらの形式のリポジトリかを先に確認します。Secretsからの移行手順はGitHub ActionsのSecrets管理|置き場所の選定と漏えい経路・OIDC移行の判断にまとめています。
OIDC導入で避けたい設計
メールアドレスをユーザーのキーにする設計
Core 5.7は、RPが安定した識別子として頼れるのは iss と sub の組だけだと定めています。発行者は同じ email を別のユーザーに再利用してよいとされており、退職者のアドレスが新入社員に割り当てられると、メールアドレスで照合しているアプリは前任者のアカウントに新入社員を入れてしまいます。複数のOPを受け入れるなら、sub だけでも不十分で、iss と組にして保存します。email_verified が true でも、そのアドレスの過去の持ち主と今の持ち主が同じ人だとは保証されません。メールアドレスが一致する既存アカウントとひも付けるときは、自動では行わず、既存アカウント側のログインもさせて両方の本人確認が済んでから連携します。
OPを自作する判断
RPを作るのとOPを作るのとでは、難しさが桁違いです。OPは鍵のローテーション、同意画面、セッション管理、ログアウト連携、Discoveryの提供まで背負います。社内の認証基盤が必要なら、KeycloakやOry Hydraのような実績のあるソフトウェアか、IDaaSを使うのが現実的です。Keycloakの立ち上げ方はKeycloakの使い方|起動から管理コンソール・DB設定と権限モデルまでで扱っています。同じ理由で、RP側もIDトークンの検証を自前のJWT解析で書かず、OpenID Foundationの認定を受けたライブラリか、上のjoseのような署名検証済みのライブラリを使います。
サーバー同士の通信(夜間バッチが別システムのAPIを呼ぶなど)は、ユーザーのログインとは別に、ワークロードの認証として設計します。呼び出し先が自社APIでOAuth 2.0のアクセストークンを受け付けるなら、クライアントクレデンシャルフローで足ります。一方、GitHub Actionsのクラウド連携やCloud Runのサービス間呼び出しのように、呼び出し先がOIDCのIDトークンを要求する構成もあるので、方式は呼び出し先の受け付ける形式に合わせます。
よくある質問
OIDCとOAuth 2.0の違いは何ですか?
OAuth 2.0はAPIを呼ぶ権限を委ねる「認可」の仕様で、OIDCはその上で「ログインしたのは誰か」を確かめる「認証」の仕様です。OIDCはOAuth 2.0の認可コードフローなどをそのまま使い、scope=openid を指定したときにIDトークンを追加で返します。
OIDCの読み方は何ですか?
OpenID Connectは「オープンアイディー・コネクト」と読みます。略称のOIDCは、アルファベットのまま「オーアイディーシー」と読むのが一般的です。
IDトークンとアクセストークンはどう使い分けますか?
ログインで受け取ったIDトークンはアプリ自身が読んでログインを成立させるためのもので、APIには送りません。アクセストークンはAPIを呼ぶときに Authorization: Bearer ヘッダーで送ります。ログイン用IDトークンの aud はアプリのclient_idなので、宛先を検証するAPIに送れば拒否されます。
IDトークンのaudとは何ですか?
そのIDトークンを受け取るべきアプリ(RP)のclient_idです。受け取ったアプリは自分のclient_idが含まれ、信頼していない値が混ざっていないことを検証します。省くと、別のアプリ向けに発行されたトークンでログインできてしまいます。
OIDCに対応しているサービスには何がありますか?
Google・Microsoft Entra ID・Apple・Auth0・Okta・Amazon Cognitoなどがあり、自社で運用するならKeycloakやOry Hydraが使えます。対応状況は各サービスの /.well-known/openid-configuration を取得すれば確認できます。