Skip to content

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

@melvincarvalho

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions