Repository navigation
Description
Summary
solid-oidc.js has asymmetric URL normalization across three iss / issuer comparison sites. The discovery-time check normalizes trailing slashes via trimSlash; the redirect-callback check and the token-validation check use strict !== with no normalization. When an IdP serves slightly different URL forms in the discovery doc vs. the redirect (or in the token's iss claim), the strict comparisons throw spurious "Issuer mismatch" errors and login fails.
This is the same defect class found in @uvdsl/solid-oidc-client-browser (issues #10 / #15 in that repo).
Sites
Site 1 — Discovery-time check (normalizes, correct)
solid-oidc.js lines 454-462:
const issuer = config.issuer
if (trimSlash(idp) !== trimSlash(issuer)) {
throw new Error(`Issuer mismatch: ${issuer} !== ${idp}`)
}
sessionStorage.setItem('solid_oidc_idp', issuer)Site 2 — Redirect-callback check (strict, no normalization)
solid-oidc.js lines 507-512:
const idp = sessionStorage.getItem('solid_oidc_idp')
const iss = url.searchParams.get('iss')
if (!idp || iss !== idp) {
throw new Error(`Issuer mismatch: ${iss} !== ${idp}`)
}Site 3 — Token validation in validateAccessToken (strict, no normalization)
solid-oidc.js lines 93-95:
if (options.issuer && payload.iss !== options.issuer) {
throw new Error(`Issuer mismatch: ${payload.iss} !== ${options.issuer}`)
}Proposed fix
Apply trimSlash consistently at all three sites. Approximate diff:
// Site 2 (line 510):
if (!idp || trimSlash(iss) !== trimSlash(idp)) {
// Site 3 (line 93):
if (options.issuer && trimSlash(payload.iss) !== trimSlash(options.issuer)) {~4 lines of code.
Why the asymmetry matters
- IdPs frequently serve different URL forms between the
.well-known/openid-configurationissuer field and the redirectissparameter (trailing slash variance is common; default-port variance also possible) - The Solid-OIDC spec inherits from RFC 9207, which requires comparison "after normalizing both values"
- Failure mode is fail-closed: legitimate logins are rejected with misleading "Issuer mismatch" errors
- Affects any user whose IdP doesn't perfectly mirror the URL form across both surfaces
Test scenario
Pseudocode for a regression test:
// Discovery doc says: issuer = "https://idp.example.com/"
// Callback redirect has: ?iss=https://idp.example.com (no trailing slash)
// Expected: login succeeds
// Current: throws "Issuer mismatch: https://idp.example.com !== https://idp.example.com/"Out of scope
- Adding stricter URL canonicalization beyond trailing-slash (default ports, case normalization, etc.) — separate work
- Issuer cross-check against WebID profile's
solid:oidcIssuertriples — that is server-side validation, see Solid-OIDC RS: missing solid:oidcIssuer profile check (steps 4–5 of the spec) JavaScriptSolidServer#510
References
- File:
solid-oidc.jsline 510 (Site 2) - File:
solid-oidc.jsline 93 (Site 3) - RFC 9207 §2.3 (URL normalization requirement): https://www.rfc-editor.org/rfc/rfc9207.html
- Related defect in
@uvdsl/solid-oidc-client-browser(closed but partial): Error when iss != idp when differ by trailing slash uvdsl/solid-oidc-client-browser#10
Activity
Bump version to 0.0.9
Bump version to 0.0.9 (#9)