Files
wbin90620 ea72467377 auth: an OAuth popup returning to / hands its answer to the opener and closes
The app's connect popup (@hanzo/app Setup) returns to
hanzo.ai/?at=-/settings/integrations with connected= or error= on the query.
MOVED moved it on to Settings with the answer dropped, and the popup stayed
open. RETURNED runs first: in a popup it posts the answer to the opener (this
origin only), a BroadcastChannel and storage, then closes the window.
2026-10-26 12:05:47 -04:00

25 lines
1.7 KiB
TypeScript

/**
* A provider's OAuth return, answered in the popup that started it.
*
* The app connects GitHub and Slack in a popup (@hanzo/app Setup, lib/oauth),
* naming `https://hanzo.ai/?at=-/settings/integrations` as its return. The API's
* callback sends the popup there with `connected=<provider>&account=<label>` or
* `error=<provider>&reason=<why>` on the query. Left alone, `/` would move the
* popup on to Settings (app/page.tsx `MOVED`) with the answer dropped, and the
* popup would stay open over a whole app while the window that opened it heard
* nothing.
*
* So this runs first, before anything is drawn: in a popup (an opener, or a
* `hanzo-oauth-` window name) it hands the answer to the opener — a message to
* this origin only, and a BroadcastChannel post and a storage write for an
* opener the popup lost — and closes. A tab with no opener, or a window the
* browser will not let a script close, goes on to Settings as before.
*
* `KEY` is @hanzo/app lib/oauth's `RETURNED`: the message type, channel and
* storage key the opener listens on.
*/
const KEY = 'hanzo-oauth-return'
export const RETURNED = `try{var q=new URLSearchParams(location.search),p=q.get('connected'),e=q.get('error');if((p||(e&&q.has('reason')))&&(window.opener||String(window.name).indexOf('hanzo-oauth-')===0)){var m=p?{type:'${KEY}',provider:p,ok:true,account:q.get('account')||''}:{type:'${KEY}',provider:e,ok:false,reason:q.get('reason')||''};try{if(window.opener)window.opener.postMessage(m,location.origin)}catch(_){}try{var b=new BroadcastChannel('${KEY}');b.postMessage(m);b.close()}catch(_){}try{localStorage.setItem('${KEY}',JSON.stringify(m));localStorage.removeItem('${KEY}')}catch(_){}window.close()}}catch(_){}`