1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code 2.1.312入門、user_id_claimは設定表に無い

1
Posted at

はじめに

Claude apps gateway を Microsoft Entra ID と組み合わせて運用していると、利用者を表す ID が id_token の sub で固定されている点に悩まされることがあります。Entra ID では利用者の識別に oid を使いたい場面が多く、sub のままでは社内の台帳と突き合わせにくいためです。

Claude Code 2.1.312 の changelog には、この悩みに応える oidc.user_id_claim が追加されたとあります。ところが、2026-10-29 時点の公式の設定リファレンスを開くと、oidc ブロックのキー表にこの設定は見当たりません。changelog にはあるのにリファレンスには無い設定を、本番の gateway.yaml に書いてよいのかという問いが残ります。

そこで本記事では、claude gateway --config が user_id_claim をどう扱うかを、IdP につながない範囲で確かめました。あわせて、同じ版で入った「短いシステムプロンプト」への切り替えの戻し方と、fullscreen のキューメッセージをクリックで送る機能も整理します。

対象読者は、Claude apps gateway を構築・運用している管理者と、Bedrock / Vertex などのクラウド経由で Claude Code を使っている開発者です。

この記事で再現できること

  • claude gateway --config に YAML を渡し、user_id_claim の書き方がスキーマに受理されるかを確かめる
  • Entra ID の oid で利用者を識別する設定を書き、IdP 側で確認すべき点を押さえる
  • カスタムのデプロイ名を使う環境で、短いシステムプロンプトから完全なプロンプトへ戻す

前提環境

検証は 2026-10-29 に、クラウド上の Linux コンテナで行いました。claude --version の出力は 2.1.312 (Claude Code) です。HOME を使い捨てのディレクトリに差し替えて実行し、手元の ~/.claude には触れていません。モデルの呼び出しと API 課金が発生するコマンドは実行していません。

TL;DR

  • oidc.user_id_claim を使うと、gateway が利用者を識別するクレームを sub 以外(Entra ID なら oid)に変えられます。claude gateway --config で試したところ、user_id_claim: oid は受理され、空文字はエラーで拒否されました
  • 公式の設定リファレンスには 2026-10-29 時点でこのキーが載っておらず、ユーザー ID は sub 由来と書かれたままです。設定の根拠は changelog と実機のスキーマ検証に置くことになります
  • Bedrock / Vertex / Foundry / Mantle で Claude Code が認識しないモデル名を使うと、2.1.312 から短いシステムプロンプトに切り替わります。元に戻すには CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT=0 を設定します

2.1.312 で変わったことのうち、本記事で扱うもの

公式の changelog によると、2.1.312 は 2026-10-27 に公開されました(GitHub の CHANGELOG.md には日付が書かれていません)。2.1.312 の節には 39 項目が並んでおり、本記事ではそのうち次の 3 項目を扱います。changelog の文言は取得ツールの要約を経由して読んだものなので、正確な表現は原文で確かめてください。

changelog の記載(要旨) 本記事での確かめ方 確認の範囲
Claude apps gateway に oidc.user_id_claim を追加し、sub 以外の id_token クレーム(例: Entra ID の oid)で利用者を識別できるようにした claude gateway --config のスキーマ検証、バイナリ内の文字列 設定の受理・拒否まで。IdP との実連携は未検証
Bedrock / Vertex / Foundry / Mantle で、認識しないモデル名(カスタムのデプロイ名や inference profile ARN)は Sonnet や Haiku を指していても短いシステムプロンプトを使う。CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT=0 で完全なプロンプトを維持できる バイナリ内の判定ロジックの読み取り 判定順序まで。実際のプロンプト差は未検証
click to send: fullscreen で、キューされたメッセージの下に出る "to send now" のヒントをクリックすると、キー操作と同じくすぐ送信される バイナリ内の文字列 表示ロジックの存在まで。実クリックは未検証

調査の途中で分かったことも書いておきます。当初は「send-now」という独立した機能や設定があると想定していましたが、2.1.312 の項目にそうした名前の設定はありません。実体は上の表の click to send で、fullscreen の UI 上のクリック操作です。claude --help にも send-now や oidc という名前のオプションはありませんでした。

手順 1: user_id_claim をスキーマ検証にかける

claude gateway には、YAML の設定ファイルを渡す --config オプションがあります。ヘルプの出力は次のとおりです。

$ claude gateway --help
Usage: claude gateway [options]
Run the enterprise auth/telemetry gateway
Options:
  --config <path>  Path to gateway YAML config
  -h, --help       Display help for command

このコマンドは起動前に設定ファイルをスキーマで検証し、問題があればエラーを列挙します。この挙動を使うと、gateway を本当に起動しなくても「そのキーが存在するか」「値の形式が合っているか」を確かめられます。

3 種類の YAML を用意する

検証には、oidc ブロックの中身だけを変えた 3 つの YAML を使いました。いずれも HOME を使い捨てのディレクトリに向けたシェルで実行しています。

ファイル oidc ブロックの差分 確かめたいこと
a.yaml user_id_claim: oid 正しい書き方が受理されるか
b.yaml user_id_claim: "" 空文字が拒否されるか
c.yaml bogus_key: oid 存在しないキーが拒否されるか

a.yaml で本記事に関係する行は次のとおりです。issuer は IdP につながないよう、ローカルの到達しないアドレスにしました。実際のファイルには client_id と client_secret にダミー値も入れています。client_id はスキーマ上の必須キーなので、省略すると出力に Required の指摘が追加されます。

a.yaml(関係する行のみ)
oidc:
  issuer: http://127.0.0.1:9/v2.0
  client_id: dummy
  client_secret: dummy
  user_id_claim: oid

実行結果

claude gateway --config a.yaml のエラー出力から message の行を抜き出すと、次のようになりました。カッコ内はどのキーへの指摘かの注記です。

"message": "Required"   (listen)
"message": "Required"   (upstreams)
"message": "oidc.issuer must be an http(s) URL and not target a cloud metadata endpoint",
"message": "Required"   (session)
"message": "Required"   (store)

listen や upstreams などの必須キーが無いこと、issuer の形式が条件を満たさないことは指摘されていますが、user_id_claim への指摘はありません。キーとしても値の形式としても受理されたと読めます。

b.yaml(空文字)では、user_id_claim を名指しした指摘が出ました。

"message": "String must contain at least 1 character(s)",
      "user_id_claim"

c.yaml(存在しないキー)では、未知のキーとして拒否されました。

"message": "Unrecognized key(s) in object: 'bogus_key'"

c.yaml の結果は、oidc ブロックが未知のキーを黙って無視しないことを示しています。もし user_id_claim がスキーマに無ければ、a.yaml でも同じ Unrecognized key(s) が出たはずです。a.yaml で出なかったことが、2.1.312 のスキーマにこのキーがある裏付けになります。

バイナリ側の定義

念のため、claude の実行ファイルに含まれる文字列も確かめました。配布物は minify(変数名の短縮)済みの JavaScript を含むため、ここで読んでいるのは変数名が短く潰されたコードです(文字列リテラルは平文のまま残っています)。その中に、次の定義がありました。

...user_id_claim:ge().min(1).optional(),userinfo_fallback:Qo().default(!1),use_pkce:...

min(1).optional() は「省略してよいが、書くなら 1 文字以上」という意味の定義として読めます。b.yaml の結果とも合っています。

手順 2: Entra ID の oid で識別する設定を書く

ここからは公式ドキュメントと changelog にもとづく内容で、実際の IdP との連携は試していません。

gateway のデプロイ手順 によると、Entra ID の issuer は https://login.microsoftonline.com/<tenant-id>/v2.0 の形です。これに user_id_claim を加えると、oidc ブロックは次のようになります。

gateway.yaml(oidc の関係する行のみ)
oidc:
  issuer: https://login.microsoftonline.com/<tenant-id>/v2.0
  user_id_claim: oid
  # client 情報・scopes など、ほかのキーは公式の設定リファレンスに従って書く

全体の流れを図にすると次のようになります。

指定したクレームが届かないときのエラー

図の「届かない」の分岐に当たるエラー文言が、バイナリ内のテンプレート文字列に次の形で入っていました(<claim> の位置に、設定したクレーム名が入ります)。

oidc.user_id_claim names `<claim>`, which the IdP did not send as a non-empty string. Check oidc.scopes, and oidc.scope_on_refresh if only refreshes fail

同じ関数では、この検査より前に sub の有無を調べる処理が走り、無ければ IdP claims missing required sub で失敗するコードも読み取れました。user_id_claim を設定しても sub は必須のままと読めますが、実際に走らせて確かめたものではありません。

文言から読み取れる確認ポイントは 2 つです。

  • 指定したクレームが、空でない文字列として id_token に入っている必要があります。一般に IdP は、要求するスコープによって含まれるクレームが変わるため、まず oidc.scopes を見直します
  • 初回のサインインは通るのにトークンの更新時だけ失敗する場合は、oidc.scope_on_refresh を確認します

このエラーが実際にどのタイミングで出るかは、IdP につないでいないため確かめていません。

隣にある groups_claim

設定リファレンス の oidc キー表には、グループを読むクレームを指定する groups_claim(既定は groups)があり、Entra ID はアプリロールを roles に出すと書かれています。利用者 ID を oid に変えるついでにロールでの制御も考えているなら、こちらも併せて見ておくとよいでしょう。

落とし穴: 公式の設定リファレンスにまだ載っていない

2026-10-29 時点の 設定リファレンス を確認したところ、oidc キー表に user_id_claim はありませんでした。gateway が上流へ付けるヘッダー x-claude-gateway-user-id の説明も、「token の sub クレームから取った IdP の subject」という趣旨のままです。

ここから運用上の注意が 2 つ出てきます。

1 つ目は、user_id_claim を設定したときに x-claude-gateway-user-id の値が oid に変わるのかが、ドキュメントからは分からないことです。上流側でこのヘッダーを台帳と突き合わせているなら、切り替え前に実際の値を確かめる必要があります。

2 つ目は、バイナリ内に IdP claims missing required `sub` という文言も残っていることです。user_id_claim を設定したあとも sub が必須として扱われるのかは、今回の手順では判断できませんでした。

もう 1 点、名前の似た別設定に注意してください。Claude Desktop on 3P の LLM gateway 向け ドキュメント には、LiteLLM の litellm_jwtauth 設定例として user_id_jwt_field: oid が載っています。これは LiteLLM 側のキーで、Claude Code 2.1.312 の oidc.user_id_claim とはキー名が違います。検索で先に見つかるのはこちらかもしれませんが、gateway.yaml に書き写しても c.yaml と同じく未知のキーとして拒否されるはずです(この組み合わせ自体は試していません)。

手順 3: 短いシステムプロンプトを元に戻す

2.1.312 では、Bedrock / Vertex / Foundry / Mantle 経由で Claude Code が認識しないモデル名を使うと、短いシステムプロンプトに切り替わるようになりました。changelog によると、カスタムのデプロイ名や inference profile ARN がこれに当たり、中身が Sonnet や Haiku であっても対象になります。

完全なプロンプトに戻すには、環境変数を 0 にして起動します。

export CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT=0
claude

判定の順序

バイナリ内の該当部分を読むと、判定は次の順で行われていました。minify 済みのコードからの読み取りで、実際の挙動を走らせて確かめたものではありません。

function M(e){if(!e)return!1;if(Le(i.CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT))return!0;if(ys(i.CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT))return!1;if(!oe(e))return!0;...

環境変数が明示されていれば、モデル名の判定より優先されます。逆に言えば、0 を設定しておけば、この判定関数の上では完全なプロンプト側に倒れます。モデルごとの設定など、ほかの経路が残っていないかは確かめていません。

短いプロンプトと完全なプロンプトで応答の質がどれだけ変わるかは、Bedrock などの環境が無いため測れていません。カスタムのデプロイ名で運用していて、2.1.312 に上げてから挙動が変わったと感じたら、まずこの変数を疑う、という使い方になります。

なお、CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT が公式の環境変数一覧に載っているかは、今回取得した範囲では確認できませんでした。

同じ版で広がった自動モデル切り替え

changelog には、フラグが立ったメッセージのあとの自動モデル切り替えも、認識しないモデル名に広げたとあります。止めたい場合は CLAUDE_CODE_DISABLE_REFUSAL_FALLBACK=1 を設定します。バイナリにも、この変数が立っていれば切り替えを行わないと読める関数がありました。

function vz(){return!i.CLAUDE_CODE_DISABLE_REFUSAL_FALLBACK&&!h2()}

カスタムのデプロイ名を使う環境では、短いプロンプトとこの自動切り替えの 2 つが同時に効き始めます。挙動の変化を切り分けるときは、片方ずつ環境変数で止めると原因を絞り込みやすくなります。

fullscreen のキューメッセージをクリックで送る

changelog によると、fullscreen 表示でメッセージをキューに入れると、その下に "to send now" のヒントが出て、クリックするとキー操作と同じくすぐに送信されます。

バイナリ内には、ヒントの文言を組み立てる次の処理がありました。

...We=D===""?"click to send now":BT({chord:D,action:"send now",format:{keyCase:"lower"}})

送信用のキーが割り当てられていないときは "click to send now"、割り当てられているときはそのキーの組み合わせ付きで "send now" を表示する、という分岐に読めます。キーを割り当てていなくてもクリックで送れる、というのが changelog の説明と合う解釈です。

実際のクリック動作は、TTY とモデル呼び出しが必要なため試していません。また、fullscreen のドキュメント を全文確認しましたが、キューメッセージのクリック送信には触れていませんでした。

確かめて分かったこと

筆者が今回の手順で一番役に立つと感じたのは、claude gateway --config のスキーマ検証を「キーの存在確認」に使えることです。oidc ブロックが未知のキーを拒否するので、ドキュメントに載っていない設定でも、受理されるかどうかで現行の版にキーがあるかを判定できます。設定リファレンスが changelog に追いついていない今回のような場面では、この確認がほぼ唯一の手がかりになりました。必須キーが欠けていてもエラーがまとめて列挙されるため、gateway を起動できる設定がまだ揃っていない段階でも使えます。

一方で、スキーマ検証で分かるのは「書いてよいか」までです。oid が実際に利用者 ID として使われるか、上流へのヘッダーの値が変わるか、sub の必須チェックが実際に先に走るかは、IdP につないで初めて分かります(コード上は先に走ると読めます)。本番に入れる前に、検証用のテナントで一度サインインし、ヘッダーの値を確かめる手順を挟むのが安全です。

短いシステムプロンプトの件は、changelog の 1 行だけだと見落としやすい変更だと感じました。Bedrock の inference profile ARN のように、モデル名がそのまま書かれていない指定を使っていると、利用者側は何も変えていないのに 2.1.312 からプロンプトが短くなります。

2.1.312 のそのほかの変更(未検証)

以下は changelog の 2.1.312 の節にある記載の一部です。動作は確認していません。

changelog の記載(要旨) 実機確認
prompt フックと agent フックを、サブエージェントを含めてセッションあたり同時 24 件までに制限 していない
利用上限のメッセージで、5 時間の枠を "session limit" ではなく "5-hour limit" と呼ぶように変更 していない
名前が不正なコマンドが 1 つあると全コマンドが読み込まれず、claude -p が何も出力しないことがある問題を修正 していない

トラブルシューティング

Q1. gateway.yaml に user_id_claim を書いたら Unrecognized key(s) が出た

2.1.312 より前の版で起動している可能性があります。claude --version で版を確かめてください。2.1.312 では、oidc ブロック直下に書いた user_id_claim は受理されました。キー名を LiteLLM 用の user_id_jwt_field など別の設定の名前にしていないかも確認します。

Q2. String must contain at least 1 character(s) が出る

user_id_claim に空文字が入っています。使わないならキーごと削除します。省略した場合は従来どおり sub が使われる、というのが changelog の説明と合う読み方です。

Q3. サインイン後に which the IdP did not send as a non-empty string が出る

指定したクレームが id_token に入っていません。oidc.scopes を見直し、更新時だけ失敗するなら oidc.scope_on_refresh も確認します(エラー文言にもとづく案内で、実際の発生は確かめていません)。

Q4. Bedrock 経由に上げてから応答の様子が変わった

カスタムのデプロイ名や inference profile ARN を使っているなら、短いシステムプロンプトに切り替わっている可能性があります。CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT=0 を設定して起動し直してください。

おわりに

2.1.312 の oidc.user_id_claim は、claude gateway --config のスキーマ検証で受理され、空文字と未知のキーは拒否されることを確かめました。公式の設定リファレンスにはまだ載っていないため、当面は changelog とスキーマ検証を根拠に書くことになります。

確かめられていないのは、IdP と連携したときの実際の識別結果、x-claude-gateway-user-id の値、sub の必須チェックの扱い、短いプロンプトの実際の差、fullscreen のクリック送信です。gateway を運用している方は、検証用のテナントでヘッダーの値を一度確かめてから本番の設定を切り替えてください。

関連記事

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?