OIDC-Login schlägt fehl, wenn nur ID-Tokens zurückgegeben werden, nach dem Upgrade auf OAuth2 2.x

Nach dem Update unserer selbst gehosteten Discourse-Umgebungen am 11. September 2026 begann der OIDC-Login mit folgendem Fehler zu scheitern:

(oidc) Authentication failure! jwt_decode_failed:
JWT::DecodeError, Nil JSON web token

Unsere ältere Entwicklungsumgebung funktionierte weiterhin einwandfrei.

Umgebung

  • Discourse läuft in Docker auf einer Azure Linux VM.
  • Azure Front Door → interner Lastausgleich → VM.
  • Discourse ist unter /forum gehostet.
  • Azure AD B2C Custom Policies für OIDC.
  • Der ausgehende Traffic der VM wird über die Azure Firewall geroutet.
  • Fehlgeschlagene Discourse-Revision: 74f839fb7.
  • Funktionierende Dev-Revision: 502aa3687.

Die relevanten Abhängigkeitsversionen waren:

Abhängigkeit Funktionierende Dev Fehlgeschlagene Produktion
oauth2 1.4.11 2.0.25
omniauth-oauth2 1.7.3 1.9.0
jwt 2.10.1 3.2.0

Das aktualisierte Repository enthält d881bf2d4aabcf2430863a96beafaeabaf915702, „DEPS: Upgrade oauth2 to 2.x“ (#43523).

Minimale Reproduktion

Dafür werden keine Netzwerkverbindung, Azure-Infrastruktur oder echte Zugangsdaten benötigt:

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}"

Mit OAuth2 1.4.11 ist der Haupt-Token leer und der ID-Token-Parameter bleibt "dummy-id".

Mit OAuth2 2.0.25 wird der Haupt-Token zu "dummy-id" und der ID-Token-Parameter wird zu nil.

Zusammenhang mit dem Discourse-Fehler

Im no-userinfo-Zweig konstruiert das OIDC-Plugin den Token mit:

::OAuth2::AccessToken.from_hash(client, response.parsed)

Später versucht es:

::JWT.decode(access_token["id_token"], nil, false).first

Wenn die Bibliothek id_token als Haupt-Token verbraucht, liefert die nachfolgende Parameterabfrage nil zurück.

Getesteter Workaround

Wir haben die Token-Konstruktion geändert, um den ID-Token aus der ursprünglichen Antwort zu erhalten:

payload = response.parsed
token = ::OAuth2::AccessToken.from_hash(client, payload)
token.params["id_token"] = payload["id_token"] if payload["id_token"]
token

Nach dem Anwenden dieses Patches und dem Neustart des UAT-Containers war der Login erfolgreich. Für diese Wiederherstellung waren keine Änderungen an Front Door, Firewall oder B2C erforderlich.

Dies erhält die bestehende Claim- und Nonce-Validierung und lässt den userinfo-Zweig unverändert.

Die rohe Live-Token-Antwort ist nicht enthalten; das Bibliothekverhalten wurde mit Fingierdaten reproduziert und der Workaround wurde über einen echten UAT-Login validiert.

Ist dies bereits durch einen Upstream-Fix abgedeckt? Andernfalls kann ich einen fokussierten PR mit Regressionsabdeckung einreichen.

1 „Gefällt mir“

Dies hätte durch Folgendes behoben werden sollen:

Bitte lass uns wissen, ob du nach dem Deployment dieses Commits weiterhin Probleme hast.

7 „Gefällt mir“

Danke. Das löst das Problem.

1 „Gefällt mir“