Microsoft Entra ID(旧 Azure AD)のアプリ登録でクライアント シークレットを更新したのに、なぜか認証エラーが消えない――その原因は「キャッシュ」ではなく、管理画面に表示される2種類の値(Secret ID と Value)を取り違えているケースが非常に多いです。この記事では、最短で復旧する手順と、再発防止の運用ポイントまでまとめます。
よくある症状:シークレット期限切れ→作り直したのに動かない
Microsoft Entra ID のアプリ登録(App registrations)で、これまで使っていたクライアント シークレットが期限切れになったため、新しいシークレットを作成してアプリ側の設定を更新した。
ところが、更新後も以下のような状態が続いてしまうことがあります。
- トークン取得に失敗して API 呼び出しができない
- 401 / 403 が返る、サインインが完了しない
- ログに “invalid client secret” や “secret is expired” といった文言が残る
- 「Secret ID(シークレット ID)」を貼り替えたのに改善しない
- 「もしかして古いシークレットがキャッシュされているのでは?」と疑ってしまう
結論から言うと、キャッシュが原因というより「入力すべき値」を誤っている可能性が高いです。
結論:アプリが使うのは Secret ID ではなく Secret Value(値)
Entra のクライアント シークレットには、管理画面上で紛らわしい2つの情報が登場します。
| 項目 | Entra 画面での表示 | 役割 | アプリの設定に入れる? | よくある誤解 |
|---|---|---|---|---|
| Secret ID(シークレット ID) | GUID のような文字列 | そのシークレットを Entra 側で識別するための「管理用 ID」 | 入れない | 「ID だから client_secret だろう」と思って貼ってしまう |
| Value(値) | ランダムな長い文字列(作成直後のみ表示) | OAuth などで実際に送信され、正当性を検証される「秘密の文字列」 | 入れる | 一度画面を離れると見えなくなり、ID を代わりに貼ってしまう |
つまり、アプリ側(設定ファイル・環境変数・Key Vault・CI/CD のシークレット変数など)に設定すべきなのは、Secret ID ではなく Valueです。
「IDが多すぎる」問題:どれをどこに入れるのか整理する
Entra のアプリ登録には “ID” が複数登場します。Secret ID と Value の混同に加えて、client_id(アプリケーション ID)やtenant_id(ディレクトリ ID)、さらにはオブジェクト IDまで出てくるため、事故が起きやすい構造です。
| 名称 | よくある表示名 | 使いどころ | アプリ設定に入れる代表例 |
|---|---|---|---|
| テナント ID | ディレクトリ(テナント)ID | どの Entra テナントに対して認証するか | tenant_id / authority の一部 |
| クライアント ID | アプリケーション(クライアント)ID | どのアプリ登録として認証するか | client_id |
| クライアント シークレットの Value | Value(値) | 秘密鍵として本人確認する(Client Credentials など) | client_secret |
| クライアント シークレットの Secret ID | ID | Entra 管理上の識別子(一覧や監査で使う) | 基本的に使わない |
| オブジェクト ID | オブジェクト ID | ディレクトリ内オブジェクトの識別(管理・参照用) | OAuth の client_id には使わない |
迷ったら、まずは「トークン取得のリクエストに載るのはどれか?」で判断すると整理しやすいです。token エンドポイントに送るのは client_id / tenant(authority)/ client_secret(Value)であり、Secret ID や オブジェクト ID は通常登場しません。
なぜ取り違えが起きるのか:見た目と用語が罠
クライアント シークレットを作成すると、一覧に「ID(識別子)」が残り続けます。一方でValue は作成直後の一度しか表示されません。そのため、
- あとから確認しようとして画面を開いたら Value が見当たらない
- 一覧に残っている Secret ID を「これが必要な値だ」と勘違いする
- 結果として client_secret に Secret ID を貼り付けてしまう
という流れが典型的です。
目安として、Secret ID はこのような形式になりがちです。
例)Secret ID: 7f2a1c0b-1234-5678-9abc-0123456789ab
一方で Value は、URL セーフな文字を含むランダムな長文になりやすく、見た目がまったく異なります(ここでは例示しませんが、一般に GUID ではありません)。
最短で復旧する:正しい更新手順(App registration)
「期限切れ後に更新したのに動かない」を最短で解消するための手順です。ポイントはValue を控えることと、アプリが参照している保存先(Key Vault / 環境変数 / CI/CD)まで確実に更新することです。
- Entra 管理センター → アプリ登録 → 対象アプリを開く
- 証明書とシークレット → クライアント シークレット → 新しいクライアント シークレット
- 説明(目的)と有効期限を設定して追加する
- 追加直後に表示される 「Value(値)」を安全な場所に控える
- この Value は画面を離れると二度と表示されません
- 後から確認できるのは Secret ID(識別子)だけです
- アプリ(または Key Vault / 設定ファイル / CI/CD のシークレット変数)に設定している
client_secretを、Secret ID ではなく Value に差し替える - 再デプロイ/再起動して、トークン取得と API 呼び出しが成功するか確認する
「作成したのに Value を控え忘れた」場合は、残念ながら Value を後から表示する方法はありません。新しいシークレットをもう一度作成し、その Value を使ってください(古いものは不要になったら削除します)。
すぐ確認できる:アプリ側の設定が本当に差し替わっているか
障害対応で一番時間を溶かすのが、「Entra では更新したつもり」なのに、実際にはアプリが古い値を参照し続けているケースです。まずはアプリが参照している client_secret の置き場所を特定し、更新が反映されているかを確認してください。
| 保存・参照場所 | 見落としやすいポイント | 確認のコツ |
|---|---|---|
| ローカルの設定ファイル(appsettings.json など) | 開発環境だけ更新して本番が古い/コミットしてはいけない値を混ぜる | 本番ではファイルではなく環境変数や Key Vault を使う運用に寄せる |
| 環境変数(App Service / Function / VM / コンテナ) | 値は更新したがプロセス再起動していない | 再起動・再デプロイ後にログで「設定源」を確認する(値は出さない) |
| CI/CD(GitHub Actions / Azure DevOps などの Secret) | パイプライン側は更新したが、デプロイ先の設定が別に存在する | 「ビルド時埋め込み」か「実行時参照」かを整理し、二重管理を避ける |
| Azure Key Vault | シークレット URI をバージョン付きで参照していると新しい値に切り替わらない | 参照が「最新追従」か「特定バージョン固定」かを必ず確認する |
| 複数環境(本番・検証・スロット) | 環境ごとに別の設定があり、一部だけ更新漏れ | 環境ごとに client_id / tenant_id / client_secret をセットで棚卸しする |
ここでのポイントは、単に「どこかに書き換えた」ではなく、実行中のプロセスが新しい値を読んでいる状態まで持っていくことです。
キャッシュが原因に見える理由:トークンと設定の“ズレ”が起きる
「キャッシュで古いシークレットが残っているのでは?」と感じるのには、実はそれなりの理由があります。ただし、起点は Entra 側のキャッシュというより、アプリ側の設定反映やトークンの寿命で説明できることが多いです。
- アクセストークンがまだ有効な間は、期限切れシークレットでも“動いているように見える”ことがある(新規トークン取得のタイミングで失敗する)
- 環境変数やシークレットストアを更新しても、プロセス再起動まで反映されない構成がある
- デプロイ先が複数(本番・ステージング・スロット)だと、片方だけ古い設定が残りやすい
- Key Vault を使っている場合、参照方法によってはバージョン固定になっていて新しい値に切り替わらない
したがって、最初に疑うべきは「Entra のキャッシュ」ではなく、アプリが参照している設定値が本当に更新されたかです。
Key Vault 利用時の注意:新しい Value を登録しただけでは切り替わらないことがある
Key Vault を使ってシークレットを管理している場合、やるべきことは単に「新しい Value を Key Vault に登録」するだけではありません。参照方法によっては、次のような落とし穴があります。
- アプリがシークレットの特定バージョンを参照している(URI にバージョンが含まれている)
- 「Key Vault 参照(Key Vault references)」を使っているが、更新後にアプリの再起動が必要
- コンテナや関数が起動時に一度だけ読み込む実装になっている
対処の方向性はシンプルです。
- 参照がバージョン固定なら、新しいバージョンに切り替える(または運用ポリシーに合わせて最新追従へ)
- 参照が最新追従でも、アプリが起動時にしか読まないなら再起動する
「Entra のシークレットを更新した」という事実と、「アプリが参照している Key Vault 上の値が更新された」という事実は別物です。両方が揃って初めて復旧します。
ログで切り分ける:代表的なエラーと意味
トークン取得の失敗は、エラーメッセージから原因をかなり絞れます。特に、Microsoft Identity Platform(OAuth2 / OpenID Connect)のエラーは“どこが違うか”を示すヒントが含まれます。
| エラーの例 | 意味(ざっくり) | 最優先で見るポイント |
|---|---|---|
| AADSTS7000215 / invalid client secret | 指定した client_secret が正しくない | Secret ID を貼っていないか/Value の更新漏れがないか |
| AADSTS7000222 / secret is expired | シークレットが期限切れ | Entra で期限切れになっていないか/複数環境のどれが期限切れか |
| unauthorized_client | アプリに許可がない、または認証方式が合っていない | 対象フロー(Client Credentials など)とアプリ設定(証明書/シークレット)が一致しているか |
| invalid_client | client_id / tenant_id の組み合わせ違い、またはシークレット違い | アプリ登録が別のものになっていないか(本番と検証の取り違え) |
特に AADSTS7000215 は「Secret ID を貼ってしまった」パターンで頻出です。Secret ID は Entra 側の管理用識別子なので、トークン エンドポイントに送っても一致しません。
手元で素早く検証する:トークン取得を最小構成で試す
アプリ全体を動かしながら切り分けるのが難しい場合は、まずはトークン エンドポイントに対して最小のリクエストで検証すると原因が見えやすくなります(実際の値は自分の環境に置き換えてください)。
POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id={client_id}
&client_secret={ここに Secret Value}
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&grant_type=client_credentials
この検証で成功するなら、Entra 側の設定よりもアプリの設定反映(どこから読み込んでいるか)が怪しい、という切り分けができます。逆にここで失敗するなら、Value の取り違えや、テナント/アプリの取り違えが疑わしいです。
それでも直らないときの追加チェック
Secret ID と Value の取り違えを直しても改善しない場合、次の“現場あるある”を上から順に潰すと復旧が早いです。
別のアプリ登録を見ている(本番と検証の取り違え)
- アプリ名が似ている、同名の登録が複数ある
- client_id(アプリケーション ID)が一致しているかを必ず確認する
- テナントが違うと、同じ名前でも別物になります
シークレットを貼った“場所”が違う(環境変数のキー名違いなど)
CLIENT_SECRETとAZURE_CLIENT_SECRETなど、キー名が複数存在- アプリが実際に読んでいるキー名をログに出せると早い(値は出さない)
- コンテナの場合、Kubernetes の Secret / ConfigMap / Helm 値のどこに入っているかを棚卸しする
アプリが“起動時に一度だけ”読み込む実装になっている
- 設定更新後に再起動しないと、古い値のまま動き続ける
- サーバーレスでも、インスタンスが温存されていると反映が遅れることがある
許可(API Permissions)や管理者の同意(Admin consent)側の問題
- シークレット更新とは無関係に、権限が不足して 403 になっている場合もある
- 認証に成功しているか(トークン取得の成否)と、認可に成功しているか(API 呼び出しの成否)を分けて考える
再発防止:クライアント シークレット運用の現実的なコツ
クライアント シークレットは扱いやすい反面、期限切れと更新漏れが起きやすい認証情報です。復旧だけでなく、次回の事故を減らすためのポイントを整理します。
有効期限は短めにし、ローテーション前提にする
クライアント シークレットの有効期限には上限があり、管理画面で選べる範囲(例:最大24か月までの選択肢が表示されることが多い)から設定します。選択肢はテナントのポリシーや UI 更新で変わることがあるため、最終的には現在のポータル表示を正として運用してください。
- 運用に慣れていないうちは 6〜12か月程度のサイクルを推奨
- 更新作業の手順書化と、期限前のリマインド(チケット化・カレンダー登録)が効果的
ローテーションは「2本立て」で切り替える
可能なら、切り替えは一発勝負にしない方が安全です。
- 新しいシークレットを追加(旧シークレットは残す)
- アプリ側を新しい Value に切り替えてデプロイ
- 動作確認後に旧シークレットを削除
この方式なら、切り替えに失敗してもすぐ戻せます。
保存は Key Vault などに寄せ、Value を手元に残さない
- Value をチャットに貼る/チケットに平文で残すのは避ける
- アプリの実行時に Key Vault から取得する、または Key Vault 参照を使う
- アクセス制御と監査ログが取れる場所に集約する
可能ならシークレットより証明書やフェデレーションへ
セキュリティや運用性の観点では、可能な範囲で次の選択肢も検討できます。
- 証明書(Certificate credentials):長期運用しやすく、漏えいリスクも下げやすい
- マネージド ID:Azure 上のリソース同士なら、そもそもシークレットを持たない構成が可能
- ワークロード ID フェデレーション(OIDC):CI/CD でシークレット配布を減らせる
まとめ:貼るべきは「Secret ID」ではなく「Value」
クライアント シークレット更新後に認証できないとき、最初に確認すべきはキャッシュではなく、アプリに設定した値が Secret ID ではなく Secret Value(値)になっているかです。
- Secret ID は「Entra 側の管理用識別子」
- Value は「認証で実際に使う秘密の文字列」
- Value は作成直後にしか表示されないため、控え忘れたら作り直す
- 更新漏れが起きやすいので、設定の置き場所(環境変数・Key Vault・CI/CD)を棚卸しする
このポイントを押さえるだけで、同じ障害の多くは短時間で復旧できます。

コメント