2026年9月11日にセルフホスト環境のDiscourseを更新した後、OIDCログインが以下のエラーで失敗するようになりました:
(oidc) Authentication failure! jwt_decode_failed:
JWT::DecodeError, Nil JSON web token
旧バージョンの開発環境は引き続き正常に動作していました。
環境構成
- Azure Linux VM上でDockerを介してDiscourseを動作させています。
- Azure Front Door → 内部ロードバランサー → VM。
- Discourseは
/forum配下でホストされています。 - OIDC用にAzure AD B2Cのカスタムポリシーを使用しています。
- VMのアウトバウンドトラフィックはAzure Firewallを介してルーティングされています。
- 失敗しているDiscourseのリビジョン:
74f839fb7。 - 正常に動作している開発環境のリビジョン:
502aa3687。
関連する依存関係のバージョンは以下の通りです:
| 依存関係 | 正常な開発環境 | 失敗している本番環境 |
|---|---|---|
| oauth2 | 1.4.11 | 2.0.25 |
| omniauth-oauth2 | 1.7.3 | 1.9.0 |
| jwt | 2.10.1 | 3.2.0 |
更新されたリポジトリには、d881bf2d4aabcf2430863a96beafaeabaf915702(「DEPS: Upgrade oauth2 to 2.x」(#43523))が含まれています。
最小再現手順
これにはネットワーク接続、Azureインフラストラクチャ、実際の認証情報はいずれも不要です:
require "oauth2"
puts Gem.loaded_specs.fetch("oauth2").version
client = OAuth2::Client.new(
"dummy",
"dummy",
site: "https://example.invalid"
)
token = OAuth2::AccessToken.from_hash(
client,
{"id_token" => "dummy-id"}
)
puts "Main token: #{token.token.inspect}"
puts "ID token parameter: #{token["id_token"].inspect}"
OAuth2 1.4.11の場合、メイントークンは空になり、IDトークンパラメータは "dummy-id" のままです。
OAuth2 2.0.25の場合、メイントークンは "dummy-id" となり、IDトークンパラメータは nil になります。
Discourseの失敗との関連性
no-userinfoブランチにおいて、OIDCプラグインは以下を使用してトークンを構築します:
::OAuth2::AccessToken.from_hash(client, response.parsed)
その後、以下を試みます:
::JWT.decode(access_token["id_token"], nil, false).first
ライブラリが id_token をメイントークンとして消費すると、その後のパラメータ検索は nil を返します。
テスト済みのワークアラウンド
トークンの構築を変更し、元のレスポンスからIDトークンを保持するようにしました:
payload = response.parsed
token = ::OAuth2::AccessToken.from_hash(client, payload)
token.params["id_token"] = payload["id_token"] if payload["id_token"]
token
このパッチを適用してUATコンテナを再起動した後、ログインに成功しました。この復旧には、Front Door、ファイアウォール、またはB2Cの変更は必要ありませんでした。
これにより、既存のクレームおよびnonceの検証が維持され、userinfoブランチは変更されません。
生のライブトークンレスポンスは含まれていません。ライブラリの動作はダミーデータで再現され、ワークアラウンドは実際のUATログインを通じて検証されました。
これはすでにアップストリームの修正でカバーされていますか?そうでなければ、リグレッションカバレッジ付きの焦点を絞ったPRを提出できます。