Skip to content

RFC 9207 iss param != discovery issuer (trailing-slash mismatch) breaks strict OIDC clients #524

Description

@melvincarvalho

Summary

The IdP advertises an issuer with a trailing slash in the discovery doc, but emits the RFC 9207 iss authorization-response parameter without one. RFC 9207 requires the iss value to be identical to the issuer identifier. Strict clients that compare them byte-for-byte reject the callback.

Where

src/idp/index.js (well-known handler):

// Ensure issuer has trailing slash for CTH compatibility
const normalizedIssuer = issuer.endsWith('/') ? issuer : issuer + '/';
const baseUrl = issuer.endsWith('/') ? issuer.slice(0, -1) : issuer;
...
issuer: normalizedIssuer,   // discovery doc => trailing slash

But the provider is created with the raw issuer:

// src/idp/provider.js:451
const provider = new Provider(issuer, configuration);

so oidc-provider's iss param (enabled via authorization_response_iss_parameter_supported: true) is the raw issuer. When the configured issuer has no trailing slash:

  • discovery issuerhttp://host:port/
  • callback isshttp://host:port

Symptom

solid-oidc (the client behind the xlogin widget) stores config.issuer from discovery and then strict-compares it to the callback iss:

// solid-oidc handleRedirectFromLogin()
if (!idp || iss !== idp) throw new Error(`Issuer mismatch: ${iss} !== ${idp}`);

(Note: its login() is slash-tolerant via trimSlash(), but handleRedirectFromLogin() is not.) The throw happens before the token request, so POST /idp/token never fires and sign-in silently bounces back to the app with no session. Reproduced embedding JSS on Android (nodejs-mobile) with idpIssuer lacking a trailing slash; tracked in #522.

Fix options

  1. Make the iss param and discovery issuer identical — feed oidc-provider the same normalized (trailing-slash) issuer used in the discovery doc, or drop the discovery-only normalization so both are slash-free.
  2. At minimum, document that the configured issuer must already carry the canonical trailing slash.

(Workaround on the embedding side: pass idpIssuer already ending in /, which makes normalizedIssuer === issuer and aligns both. That fixed sign-in for the Android app.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions