Skip to content

OIDC token endpoint rejects public clients with invalid_client (regression from #452) #513

Description

@melvincarvalho

Summary

xlogin (and any Solid app using dynamic client registration with token_endpoint_auth_method: "none") can complete the authorization code flow against JSS but cannot exchange the code for tokens — the token endpoint returns 401 invalid_client. This is blocking login across the solid-apps suite (explorer, plaza, timeline, hub-mashlib all hit it).

Reproduced against JSS at HEAD (commit fdc219f, package.json says 0.0.201).

Repro

jss start \
  --port 5446 \
  --host localhost \
  --root /tmp/jss-test/pod-data \
  --single-user \
  --single-user-password test \
  --idp \
  --notifications \
  --mashlib-module <any solid app entry>

Visit http://localhost:5446/public/ in a browser, click any Solid app's Login button (e.g. xlogin's), enter username/password.

  1. POST /idp/interaction/<id>/login → 302 (login succeeds)
  2. Browser redirected back to the app with ?code=...
  3. xlogin posts to /idp/token with the code → 401 invalid_client

Log excerpt

err: invalid_client
stack: InvalidClientAuth: invalid_client
    at authenticateClient (oidc-provider/lib/shared/client_auth.js:166:17)
    at async setWWWAuthenticateHeader (oidc-provider/lib/shared/client_auth.js:49:11)
    at async selectiveBody (oidc-provider/lib/shared/selective_body.js:49:5)
error_description: "client authentication failed"
msg: "oidc-provider grant error"

POST /idp/token statusCode=401 contentLength=77 responseTime=1.74ms

Body length 77 bytes is consistent with the standard public-client payload (grant_type=authorization_code&code=...&redirect_uri=...&client_id=...&code_verifier=...) — no client_secret, which is correct for a none-auth client.

Why this matters

This isn't an xlogin-specific problem. It's the OIDC token endpoint refusing every public client. Public clients are the canonical Solid flow: browser-based apps that dynamically register and authenticate per-session via PKCE alone. If JSS's token endpoint can't honour that, no in-browser Solid app can log in — including:

  • solid-apps/explorer (logging in to read private containers)
  • solid-apps/plaza (logging in to post)
  • solid-apps/timeline (logging in to post)
  • solid-apps/hub (via the new hub-mashlib.js data-browser bundle, just spiked)
  • Any third-party Solid client using @inrupt/solid-client-authn-browser or similar

Suspected origin

PR #452 (merged 2026-05-14, included in JSS 0.0.194+) reworked stale-session-cookie + consent-crash recovery. It touched src/idp/provider.js and src/idp/interactions.js. The token endpoint went from working (≤ 0.0.193) to silently rejecting public clients sometime after that merge.

Relevant code paths:

  • src/idp/provider.js:341token_endpoint_auth_method: 'none' is in clientDefaults, so dynamically-registered clients SHOULD inherit none. They're being rejected anyway, so either the default isn't taking effect or oidc-provider's client-auth check is over-strict for the none path.
  • src/idp/provider.js:379 — there's a CORS branch on client.tokenEndpointAuthMethod === 'none' that exists, suggesting we knew about this case at some point.

Suggested investigation

  1. Inspect the dynamically-registered client record in the IdP adapter — confirm token_endpoint_auth_method is being persisted as none after POST /idp/reg.
  2. Trace authenticateClient in oidc-provider's client_auth.js:166 — what client metadata is it seeing for these requests? Is it expecting client_secret_basic or client_secret_post when it should accept the none path?
  3. Diff provider.js against pre-OIDC server_error after account delete + re-create (stale session) #452 — anything in the client-auth or grant-type pipeline that would affect public-client acceptance?
  4. Consider whether expireSessionCookiesKoa or the stale-session redirect is corrupting state in a way that makes the subsequent /idp/token request appear to be on a different client.

Workaround

Pin JSS to 0.0.193 in package.json (and npm install) to restore login. This is what jspod / nosdav-server consumers may need to do until the fix lands.

Related

  • The solid-apps suite of in-browser Solid clients all share this dependency. Fixing the token endpoint unblocks all of them at once.
  • Earlier conversation in the issue tracker about the same observation (search: invalid_client, regression).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions