Il login OIDC fallisce con risposte solo ID-token dopo l'aggiornamento a OAuth2 2.x

Dopo l’aggiornamento dei nostri ambienti Discourse self-hosted l’11 settembre 2026, l’accesso tramite OIDC ha iniziato a fallire con:

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

Il nostro ambiente di sviluppo più vecchio continuava a funzionare.

Ambiente

  • Discourse eseguito in Docker su una VM Azure Linux.
  • Azure Front Door → bilanciatore del carico interno → VM.
  • Discourse ospitato sotto /forum.
  • Policy personalizzate di Azure AD B2C per OIDC.
  • Traffico in uscita dalla VM instradato tramite Azure Firewall.
  • Revisione Discourse con errore: 74f839fb7.
  • Revisione di sviluppo funzionante: 502aa3687.

Le versioni rilevanti delle dipendenze erano:

Dipendenza Dev funzionante Produzione con errore
oauth2 1.4.11 2.0.25
omniauth-oauth2 1.7.3 1.9.0
jwt 2.10.1 3.2.0

Il repository aggiornato include d881bf2d4aabcf2430863a96beafaeabaf915702, “DEPS: Upgrade oauth2 to 2.x” (#43523).

Riproduzione minima

Questo non richiede connessione di rete, infrastruttura Azure o credenziali reali:

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

Con OAuth2 1.4.11, il token principale è vuoto e il parametro ID token rimane "dummy-id".

Con OAuth2 2.0.25, il token principale diventa "dummy-id" e il parametro ID token diventa nil.

Collegamento con il fallimento di Discourse

Nella branch senza userinfo, il plugin OIDC costruisce il token utilizzando:

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

In seguito, tenta:

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

Quando la libreria consuma id_token come token principale, la successiva ricerca del parametro restituisce nil.

Workaround testato

Abbiamo modificato la costruzione del token per preservare l’ID token dalla risposta originale:

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

Dopo l’applicazione di questa patch e il riavvio del container UAT, l’accesso ha avuto successo. Non sono state necessarie modifiche a Front Door, firewall o B2C per quel recupero.

Questo preserva la convalida esistente di claim e nonce e lascia invariata la branch userinfo.

La risposta del token live grezzo non è inclusa; il comportamento della libreria è stato riprodotto con dati fittizi e il workaround è stato validato tramite un accesso UAT reale.

Questa è già coperta da una fix upstream? In caso contrario, posso inviare un PR mirato con copertura di regressione.

1 Mi Piace

Questo dovrebbe essere stato risolto da:

Fateci sapere se riscontrate ancora problemi dopo aver applicato quel commit.

7 Mi Piace

Grazie. Questo risolve il problema.

1 Mi Piace