fix(browser): re-register when the OIDC provider no longer knows the stored client - #4356
Open
jeswr wants to merge 1 commit into
Open
fix(browser): re-register when the OIDC provider no longer knows the stored client#4356jeswr wants to merge 1 commit into
jeswr wants to merge 1 commit into
Conversation
…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>
There was a problem hiding this comment.
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 fromsilentlyAuthenticatewhenKEY_CURRENT_URLindicates 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); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
clientIdis no longer known to the provider. On session restore,silentlyAuthenticateredirects to the authorization endpoint with the staleclientIdandprompt=none. The provider cannot redirect the error back (it can't validate theredirect_uriof an unknown client), so it returns a non-redirectable "unknown client" error (e.g. Community Solid Server returns400 E0003 Unknown client). BecauseKEY_CURRENT_URLis only cleared after a successful silent auth, the next load re-attempts with the same rejectedclientId— 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
silentlyAuthenticatenow detects an incomplete previous attempt (aKEY_CURRENT_URLstill 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 bysilentlyAuthenticate.Session.spec.ts; CHANGELOG "Unreleased → Bugfixes" entry.Notes / trade-offs
KEY_CURRENT_URLis 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.SessionInfoManager. I'm happy to promoteclearClientRegistrationInfotoISessionInfoManager(and add a node implementation) if you'd rather have it on the interface.Checklist
packages/browser/src/Session.spec.ts)