fix(auth): surface exact OIDC issuer mismatches (#1666)

* fix(auth): surface exact OIDC issuer mismatches

* fix(auth): align issuer mismatch hint with tests

---------

Co-authored-by: SureBot <sure-bot@we-promise.com>
This commit is contained in:
Sure Admin (bot)
2026-05-05 00:47:45 +02:00
committed by GitHub
parent a108e6501e
commit 0954200ad4
3 changed files with 61 additions and 7 deletions

View File

@@ -111,10 +111,21 @@ export default class extends Controller {
if (response.ok) {
const data = await response.json()
if (data.issuer) {
// Valid OIDC discovery endpoint
issuerInput.classList.remove('border-yellow-300', 'border-red-300')
issuerInput.classList.add('border-green-300')
this.showValidationMessage(issuerInput, 'Valid OIDC issuer', 'success')
if (data.issuer === issuer) {
issuerInput.classList.remove('border-yellow-300', 'border-red-300', 'border-amber-300')
issuerInput.classList.add('border-green-300')
this.showValidationMessage(issuerInput, 'Valid OIDC issuer', 'success')
} else {
issuerInput.classList.remove('border-yellow-300', 'border-green-300')
issuerInput.classList.add('border-amber-300')
const trailingSlashOnly = data.issuer.replace(/\/$/, '') === issuer.replace(/\/$/, '')
const message = trailingSlashOnly
? `Issuer mismatch: discovery returned ${data.issuer}. This is usually a trailing slash mismatch, so copy the issuer exactly as returned.`
: `Issuer mismatch: discovery returned ${data.issuer}. Copy the issuer exactly as returned by the provider.`
this.showValidationMessage(issuerInput, message, 'warning')
}
} else {
throw new Error('Invalid discovery response')
}

View File

@@ -63,11 +63,14 @@ class SsoProviderTester
)
end
# Check if issuer matches
if discovery["issuer"] != provider.issuer && discovery["issuer"] != provider.issuer.chomp("/")
# Check if issuer matches exactly. OIDC discovery requires the configured
# issuer string to be identical to the issuer returned by the provider.
if discovery["issuer"] != provider.issuer
hint = trailing_slash_hint(provider.issuer, discovery["issuer"])
return Result.new(
success?: false,
message: "Issuer mismatch: expected #{provider.issuer}, got #{discovery["issuer"]}",
message: [ "Issuer mismatch: expected #{provider.issuer}, got #{discovery["issuer"]}", hint ].compact.join(". "),
details: { expected: provider.issuer, actual: discovery["issuer"] }
)
end
@@ -204,4 +207,10 @@ class SsoProviderTester
def faraday_client
@faraday_client ||= Faraday.new(ssl: self.class.faraday_ssl_options)
end
def trailing_slash_hint(expected, actual)
return unless expected.to_s.chomp("/") == actual.to_s.chomp("/")
"trailing slash mismatch. This usually means the issuer URL differs only by a trailing slash. Update the configured issuer to exactly match the discovery document"
end
end