Detect auth scope changes across app updates#1353
Draft
silverbucket wants to merge 2 commits intomasterfrom
Draft
Detect auth scope changes across app updates#1353silverbucket wants to merge 2 commits intomasterfrom
silverbucket wants to merge 2 commits intomasterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds core support in rs.js for detecting when an app’s currently claimed access scope differs from the last authorized scope for the active backend, and exposes that state via a sticky event and helper.
Changes:
- Persist “pending” and “authorized” OAuth scopes in
localStorage, normalize them, and compare against the currently claimed scope. - Emit a sticky
scope-change-requiredevent (with areauthorize()helper) and exposescopeChangeRequiredstate. - Add unit tests covering scope drift detection and promotion of pending → authorized scope on successful authorization.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/remotestorage.ts | Implements scope normalization, persistence, drift detection, sticky event emission, and reauthorize() alias. |
| src/authorize.ts | Stores pending scope before redirect and completes scope persistence on successful auth; clears pending on error paths. |
| src/access.ts | Notifies RemoteStorage when claimed scopes change so drift detection can run immediately. |
| test/unit/remotestorage.test.mjs | Adds tests for sticky scope-change-required event and clearing drift state after auth completion. |
| test/unit/authorize.test.mjs | Adds tests for pending-scope storage on authorize and authorized-scope promotion on token exchange completion. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
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.
Summary
This adds first-class detection for auth scope changes after an app has already been authorized.
When an app loads with a different claimed scope than the one last authorized for the current backend, rs.js now stores that mismatch as library state and emits a sticky
scope-change-requiredevent with areauthorize()helper.Problem
Today, if a user is already authenticated and an app ships an update that changes the scope it claims, rs.js does not detect that scope drift proactively.
That creates a poor experience for both cases:
Apps using the remoteStorage widget should not have to build their own detection logic for this. The core library should know when the currently requested scope differs from the last authorized one.
What this changes
scope-change-requiredevent so UIs attaching later can still react.reauthorize()alias forreconnect()to make the permission refresh flow more explicit.Why this approach
The goal here is not to interpret whether a scope change is broader or narrower. The important signal is simply that the app's current requested scope no longer matches the last authorization state. Keeping that comparison simple makes the behavior predictable and lets widget-based apps handle the UX centrally without requiring per-app code.
Non-widget apps
Apps that do not use the widget can hook into this directly with the new event surface:
That means custom UIs do not need to implement their own scope persistence or comparison logic. They only need to decide how to present the message to the user.
Widget users
The intention is that widget users should not need any app changes for this once the widget adopts the new core event. The widget can listen for
scope-change-requiredand show a built-in refresh-permissions message/action.Testing
./node_modules/.bin/tsc --pretty false./node_modules/.bin/mocha test/unit/remotestorage.test.mjs test/unit/authorize.test.mjsFollow-up
This PR adds the core detection and event surface in rs.js. The built-in user-facing message for widget users should be implemented in the separate
remotestorage-widgetrepo by listening forscope-change-requiredand offering a refresh-permissions action.