Skip to content

feat: add sign-in flow for crossOriginIsolated contexts#3253

Draft
velzie wants to merge 2 commits into
HeyPuter:mainfrom
velzie:feat/coi-login
Draft

feat: add sign-in flow for crossOriginIsolated contexts#3253
velzie wants to merge 2 commits into
HeyPuter:mainfrom
velzie:feat/coi-login

Conversation

@velzie

@velzie velzie commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

adds an alternative to the postMessage auth flow for puterjs that works when cross origin isolated

@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.

So the general idea is right, but this would be creating 1 new channel per request, which might get expensive like we talked about in the call.

I think the better approach for our backend architecture would be to expand BroadcastService to relay outer.pubsub.* events through one dedicated channel.

the general logic would be that you'd set up a channel on boot for all nodes connected to a given redis instance

class BroadcastService {
#redisChannel = 'broadcast:pubsub';
// whatever else
#redisRelayKeys = ['outer.pubsub', 'pubsub'] // for peers and local if needed
#redisSub: ReturnType<typeof this.clients.redis.duplicate> | null = null;

#subscribeRedisOutbound(){
  // redis sub and register handler to relay via event client, see the webhook path
  // note youll probably need some random uuid based dedup
  this.redisSub = someSub;
}

override onServerStart(): void {
    this.#loadConfig();
    this.#subscribeOutbound();      // existing webhook path
    this.#subscribeRedisOutbound(); // local bus -> Redis publish
}

override async onServerPrepareShutdown(): Promise<void> {
    // ...existing flush code...
    if (this.#redisSub) {
        try {
            await this.#redisSub.unsubscribe(this.#redisChannel);
            await this.#redisSub.quit();
        } catch (err) {
            console.warn('[broadcast] redis sub teardown failed', err);
        }
        this.#redisSub = null;
    }
  }
}

Note: im suggesting both outer.pubsub, and pubsub in case you want just regional support for this, you might not need this however

with that you could do something like this to listen to an event in one endpoint

// 'outer.' gets stripped when digested IIRC
this.clients.event.on(`pubsub.login.${someKey}`, (data,meta) => {
  resolve(data.whatever)
});
const result = await promise;
// do whatever
this.clients.event.clearListener(`outer.pubsub.login.${someKey}`); // TODO: implement this clearListener

and do something like this on the other end to emit it

this.clients.event.emit(`outer.pubsub.login.${someKey}`);

Let me know if any of this doesn't make sense happy to sync on it

if (!token) {
const subscriber = this.clients.redis.duplicate();

token = await new Promise<string | null>(async (resolve) => {

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.

nit: can probably do to make it easier to read

const {resolve, promise, reject} = Promise.withResolver();

callEvent(()=>... resolve());

await promise;

const subscriber = this.clients.redis.duplicate();

token = await new Promise<string | null>(async (resolve) => {
const timeout = setTimeout(() => resolve(null), 10000);

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.

nit: can probably use Promise.race(promise,timeoutPromise)

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.

2 participants