Skip to content

fix(browser): re-register when the OIDC provider no longer knows the stored client - #4356

Open
jeswr wants to merge 1 commit into
inrupt:mainfrom
jeswr:fix/reregister-on-unknown-client
Open

fix(browser): re-register when the OIDC provider no longer knows the stored client#4356
jeswr wants to merge 1 commit into
inrupt:mainfrom
jeswr:fix/reregister-on-unknown-client

Conversation

@jeswr

@jeswr jeswr commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #4355.

Description

When a Solid OIDC provider drops a browser's dynamically-registered client (e.g. it kept client registrations in memory and restarted), the browser's stored clientId is no longer known to the provider. On session restore, silentlyAuthenticate redirects to the authorization endpoint with the stale clientId and prompt=none. The provider cannot redirect the error back (it can't validate the redirect_uri of an unknown client), so it returns a non-redirectable "unknown client" error (e.g. Community Solid Server returns 400 E0003 Unknown client). Because KEY_CURRENT_URL is only cleared after a successful silent auth, the next load re-attempts with the same rejected clientId — looping indefinitely. The user's session appears permanently broken, and the retry storms add load to the provider. Observed in production against Community Solid Server (solidcommunity.net), where it surfaced as rate-limiting (429s).

Change

silentlyAuthenticate now detects an incomplete previous attempt (a KEY_CURRENT_URL still set on re-entry) and, instead of retrying, discards the stored dynamic client registration and stops. The next login registers a fresh client and recovers automatically.

  • SessionInfoManager.clearClientRegistrationInfo(sessionId) — targeted removal of just the dynamic client registration keys (clientId, clientSecret, clientType, clientName, expiresAt, idTokenSignedResponseAlg); the rest of the session is left intact.
  • ClientAuthentication.clearClientRegistrationInfo(sessionId) — public passthrough used by silentlyAuthenticate.
  • Regression test in Session.spec.ts; CHANGELOG "Unreleased → Bugfixes" entry.

Notes / trade-offs

  • KEY_CURRENT_URL is shared across tabs, so a concurrent silent auth in another tab could be interpreted as an incomplete previous attempt and trigger a re-registration. This is recoverable (the next login re-registers) and strictly better than the current infinite loop; happy to refine (e.g. a dedicated per-attempt marker) if you'd prefer.
  • The change is contained to the browser package with a typed cast to the concrete SessionInfoManager. I'm happy to promote clearClientRegistrationInfo to ISessionInfoManager (and add a node implementation) if you'd rather have it on the interface.

Checklist

  • Unit test for the regression (packages/browser/src/Session.spec.ts)
  • CHANGELOG updated (Unreleased → Bugfixes)
  • All affected browser specs pass; lint clean

…stored client

When a Solid OIDC provider drops a browser's dynamically-registered client (e.g. it
kept registrations in memory and restarted), silent authentication redirects to the
provider, receives a non-redirectable 'unknown client' error, and — because the
KEY_CURRENT_URL marker is only cleared after a *successful* silent auth — retries
indefinitely with the same rejected client ID. The user's pod appears permanently
broken and the retries add load to the provider.

On re-entering silent authentication with KEY_CURRENT_URL already set (i.e. the
previous attempt never completed), discard the stored client registration and stop,
so the next login re-registers a fresh client and recovers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
@jeswr
jeswr requested a review from a team as a code owner August 6, 2026 09:18
Copilot AI lite review requested due to automatic review settings August 6, 2026 09:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses an infinite silent-authentication loop in the browser package when an OIDC provider no longer recognizes a previously dynamically-registered client (e.g., after provider restart). It avoids repeated prompt=none redirects with a stale clientId by detecting an incomplete prior silent-auth attempt and clearing the stored client registration so a subsequent login can re-register.

Changes:

  • Add targeted removal of stored dynamic client registration fields via SessionInfoManager.clearClientRegistrationInfo(sessionId).
  • Add a ClientAuthentication.clearClientRegistrationInfo(sessionId) passthrough and invoke it from silentlyAuthenticate when KEY_CURRENT_URL indicates a previous silent-auth attempt never completed.
  • Add a regression test covering the non-looping behavior and update the Unreleased changelog.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/browser/src/sessionInfo/SessionInfoManager.ts Adds targeted deletion of dynamic client registration keys from storage.
packages/browser/src/Session.ts Detects incomplete prior silent-auth via KEY_CURRENT_URL, clears registration, and stops instead of retrying.
packages/browser/src/Session.spec.ts Adds regression coverage ensuring the library clears registration and does not re-attempt silent auth.
packages/browser/src/ClientAuthentication.ts Adds a public passthrough to clear client registration via the session info manager.
CHANGELOG.md Documents the bugfix in the Unreleased section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +117 to +121
clearClientRegistrationInfo = async (sessionId: string): Promise<void> => {
await (
this.sessionInfoManager as SessionInfoManager
).clearClientRegistrationInfo(sessionId);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Silent authentication loops forever when the OIDC provider no longer knows the stored dynamic client

2 participants