mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
Every import, the catalog pin and the docs name @hanzo/app and github.com/hanzoai/app. lib/rooms.ts is lib/app.ts and components/rooms.tsx is components/app.tsx.
64 lines
2.5 KiB
TypeScript
64 lines
2.5 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* /auth/logout — the sign-out another Hanzo site on the web leaves through.
|
|
*
|
|
* platform.hanzo.ai signs in on hanzo.ai, so the IAM session that answers it is
|
|
* kept on THIS origin (host-only, universe static-sites `iam-on-hanzo-ai`), where
|
|
* that site cannot reach it. Its sign-out hands back its own tokens and then sends
|
|
* the browser here with `?to=` naming where it lands. This page first ends the
|
|
* session with IAM's `everywhere` (`end`), which retires the person's grant to
|
|
* every Hanzo app with it, then signs out the way hanzo.ai's own sign-out does
|
|
* (@hanzo/ui/auth `signOut`), so neither site is left signed in and the next
|
|
* sign-in on either is typed.
|
|
*
|
|
* `to` is followed only to a Hanzo site on the web (lib/auth/asker `ours`);
|
|
* anything else lands on this site's own sign-in, as a sign-out here does. The
|
|
* silent ask for a session is spent first (`asked`): this tab is the one ending it.
|
|
*/
|
|
import { useEffect, useRef } from 'react'
|
|
import { useIam } from '@hanzo/iam/react'
|
|
import { useI18n } from '@hanzo/i18n/react'
|
|
import { signOut } from '@hanzo/ui/auth'
|
|
import { Wait } from '@/components/shell/focus'
|
|
import { asked } from '@hanzo/app/lib/session'
|
|
import { OUT } from '@hanzo/app/lib/signout'
|
|
import { track } from '@hanzo/app/lib/tags'
|
|
import { ours } from '@/lib/auth/asker'
|
|
|
|
/**
|
|
* End IAM's session on this origin and every grant of the client's organization
|
|
* (hanzoai/iam logout `everywhere`). First, because the session cookie is what
|
|
* names the person: `signOut`'s own end-session call that follows finds none.
|
|
*/
|
|
async function end(clientId: string) {
|
|
try {
|
|
await fetch('/v1/iam/oauth/logout', {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
redirect: 'manual',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: new URLSearchParams({ client_id: clientId, everywhere: 'true' }).toString(),
|
|
})
|
|
} catch {
|
|
// signOut below still hands back this site's tokens and ends the session.
|
|
}
|
|
}
|
|
|
|
export default function Logout() {
|
|
const { sdk, config } = useIam()
|
|
const { t } = useI18n()
|
|
// Once per page: the sign-out leaves it.
|
|
const started = useRef(false)
|
|
|
|
useEffect(() => {
|
|
if (started.current) return
|
|
started.current = true
|
|
const to = new URLSearchParams(window.location.search).get('to')
|
|
asked()
|
|
void end(config.clientId).then(() => signOut(sdk, { to: to && ours(to) ? to : OUT, clientId: config.clientId, track }))
|
|
}, [sdk, config.clientId])
|
|
|
|
return <Wait title={t('Signing out')} />
|
|
}
|