Files
hanzo.ai/app/(marketing)/auth/logout/page.tsx
zeekay 6c65e3e941 @hanzo/app 0.2.0: the app SDK, renamed from @hanzo/rooms
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.
2026-10-22 19:07:20 -07:00

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')} />
}