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을 제출할 수 있습니다.