Skip to content

feat: add sign-in flow for crossOriginIsolated contexts, take two#3338

Open
velzie wants to merge 8 commits into
HeyPuter:mainfrom
velzie:feat/coi-login
Open

feat: add sign-in flow for crossOriginIsolated contexts, take two#3338
velzie wants to merge 8 commits into
HeyPuter:mainfrom
velzie:feat/coi-login

Conversation

@velzie

@velzie velzie commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@Salazareo

Copy link
Copy Markdown
Member

@ProgrammerIn-wonderland @velzie what was the issue that caused this to be reverted earlier?

@ProgrammerIn-wonderland

Copy link
Copy Markdown
Collaborator

the function which listened on onmessage for the iframe in the non cross origin codepath was called with empty parameters on accident

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a fallback sign-in mechanism for crossOriginIsolated contexts by routing the auth token through backend long-polling + Redis pub/sub fanout instead of relying solely on postMessage between opener/popup.

Changes:

  • Frontend: puter.auth.signIn() now includes a signin_session and polls /login/wait in crossOriginIsolated mode.
  • GUI: popup sign-in path posts the token to /login/set when cross_origin_isolated=true, and common post-auth behaviors were refactored into postAuthActions().
  • Backend: introduces /login/wait and /login/set, adds an EventClient.off() API, and extends BroadcastService with Redis pub/sub-based intra-cluster fanout.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/puter-js/src/modules/Auth.js Adds COI-specific sign-in session + backend polling; adjusts popup handling.
src/gui/src/initgui.js Extracts post-auth flows and adds COI popup token handoff via /login/set.
src/backend/services/broadcast/BroadcastService.ts Adds Redis pub/sub fanout layer and source-loop prevention for replicated events.
src/backend/controllers/auth/AuthController.ts Adds /login/wait and /login/set endpoints for token rendezvous.
src/backend/clients/event/types.ts Adds typed pubsub.login.* event key.
src/backend/clients/event/EventClient.ts Adds off() to unregister event listeners.

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

Comment on lines +72 to +96
if ( window.crossOriginIsolated ) {
(async () => {
while (true) {
try {
const result = await fetch(`${this.APIOrigin}/login/wait`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ session: signinsession }),
});

if ( result.ok ) {
const { auth_token } = await result.json();
if (settled) return;
settled = true;
cleanup();
puter.setAuthToken(auth_token);
resolve({ success: true, token: auth_token });
return '';
}
} catch {}
await new Promise(r => setTimeout(r, 1000));
}
})();
Comment on lines +167 to +171
const popup = openAuthPopup(url);
if ( !window.crossOriginIsolated ) {
// cannot watch in isolated mode
watchPopup(popup);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

annoyingly enough you can't even check the closed status of cross origin isolated windows so this was intentional

Comment thread src/gui/src/initgui.js
Comment on lines +127 to +141
if (isolated) {
let data = await window.getUserAppToken(new URL(window.openerOrigin).origin);
await fetch(`${window.api_origin}/login/set`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
auth_token: data.token,
session: session,
}),
})
window.close();
window.open('', '_self').close();
} else {
Comment on lines +113 to +132
const { resolve, promise } = Promise.withResolvers<void>();

let token: string | null = null;
const listener = (_key: string, value: { authtoken: string }) => {
token = value.authtoken;
resolve();
};
this.clients.event.on(`pubsub.login.${session}`, listener);

const timeout = new Promise<void>((resolve) =>
setTimeout(resolve, 10000),
);
await Promise.race([promise, timeout]);
if (!token) {
throw new HttpError(408, 'Request timeout.', {
legacyCode: 'request_timeout',
});
}
this.clients.event.off(`pubsub.login.${session}`, listener);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this looks legit @velzie

Comment thread src/backend/controllers/auth/AuthController.ts
Comment thread src/backend/services/broadcast/BroadcastService.ts
Comment thread src/backend/services/broadcast/BroadcastService.ts
Comment thread src/backend/services/broadcast/BroadcastService.ts
Comment thread src/backend/controllers/auth/AuthController.ts
@velzie

velzie commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

should be resolved

@Salazareo Salazareo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if couple copilot flags are resolved then I think this looks good

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.

4 participants