Repository navigation
🐛 fix: make the Microsoft sign-in survive one click - #80
Merged
Merged
Conversation
Two defects, both of which end the same way: back on the sign-in screen instead of at the vault. The window opened after an await. Building the authorize URL needs the PKCE challenge, which is a real SHA-256 that the platform settles off the event loop — so a whole task passed between the click and `window.open`, and a browser is entitled to decide nobody asked for that window. It opens empty now, while the click is still fresh, and is pointed at Microsoft once the address exists. The way home needed `window.opener`. A Cross-Origin-Opener-Policy on the sign-in page severs it, and Microsoft already sends that header in report-only mode — which is how a site announces what it is about to enforce. With the opener gone the callback said "not ours" and the popup went on to boot an entire vault into itself, so what a person saw was the sign-in screen again, in a smaller window. The state prefix is ours and nothing else writes it, so that alone identifies the callback now, and the code comes back over a BroadcastChannel as well, which does not care who opened whom. The closed-window watch had to learn the difference too: a severed handle reads as closed from the start, and treating that as a cancellation would abandon a sign-in in progress. One synchronous look at the moment of opening tells a stub from a real window, so a real close is still noticed immediately. The test that went flaky on CI last week was this same fact about the digest, reported from the other side. I fixed the test and did not listen to it.
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.
Edgar signed in to OneDrive and it worked, but only after logging in three times before reaching the create-master-password screen. Two defects, both ending the same way: back on the sign-in screen instead of at the vault.
The window opened after an await
Building the authorize URL needs the PKCE challenge, and that is a real SHA-256 the platform settles off the event loop — not in a microtask. So a whole task passed between the click and
window.open, and a browser is entitled to decide nobody asked for that window.It now opens empty while the click is still fresh, and is pointed at Microsoft once the address exists.
The regression test is the shape of the bug, not a re-description of the fix:
The way home needed
window.openerA Cross-Origin-Opener-Policy on the sign-in page severs the opener, and Microsoft already sends it:
Report-only does not sever today, but it is how a site announces what it is about to enforce. And with the opener gone the callback said "not ours" and the popup went on to boot an entire vault into itself — so what a person saw was the sign-in screen again, in a smaller window, which is a fair description of "I had to log in three times".
The state prefix is ours and nothing else writes it, so that alone identifies the callback now. The code comes back over a
BroadcastChannelas well, which does not care who opened whom, only that both sides are this origin. If the browser then refuses to close the window, it says what it is instead of rendering a vault.The closed-window watch had to learn the same difference: a severed handle reads as
closedfrom the start, and treating that as a cancellation would abandon a sign-in in progress. One synchronous look at the moment of opening tells a stub from a real window — after which a real close is still noticed immediately, with no grace period to sit through.Tests
24 in
ms-auth.test.ts, up from 19. Four mutations, four failures, including putting yesterday's bug back exactly as it was:openerin the callback againnpm test383 green · build clean · smoke suite 229 green.What I got wrong
The unit test that went flaky on CI last week — #79 — was this same fact about the digest, reported from the other side. I fixed the test and did not stop to ask what it was telling me about the product. It was telling me the window opens too late.
Still open, and it is a decision rather than a bug
The Microsoft refresh token is kept in memory only, so every page reload means a full interactive sign-in again. That was deliberate in #78 — a refresh token written to disk is a standing key to someone's files — but it is a trade worth making on purpose rather than by default, and it is the next thing Edgar will notice.