Authentication flow
How sessions, cookies, and identity are propagated across xcity.one and its sub-products.
The 30-second model
user logs in once on → xcity-home sets a host-only
www.xcity.one (GoTrue) SameSite=Lax session cookie
user visits chat.xcity.one
app boots →
fetch('https://www.xcity.one/api/me/litellm-key',
{ credentials: 'include' })
↑ browser auto-attaches the cookie because *.xcity.one is same-site
↑ xcity-home returns: { key, plan, models, api_base }
app hits tokenhub.xcity.one/v1/{models,chat/completions} with bearer
↑ tokenhub enforces the user's plan whitelist + budget per request
Three BFF endpoints do all the work — sub-products never call GoTrue, Stripe, or LiteLLM admin APIs directly.
Why this shape
- Single sign-on without OAuth dance. Users log in once at
www.xcity.oneand their session works across every*.xcity.onesub-product, with no per-product redirect. - Sub-products hold no secrets. They never see the user’s password, refresh token, or LiteLLM master key. The worst-case compromise of a sub-product is a leaked short-lived inference key.
- Centralized policy. Plan whitelists, model gating, and budget enforcement live in one place (xcity-home + LiteLLM) — sub-products can’t drift from policy.
Production vs dev
In production the session cookie is Secure, so cookies will not attach to plain http:// hosts. For local development, allow your dev origin via XCT_CORS_EXTRA_ORIGINS=http://localhost:3000.
Desktop (Electron)
Browser cookie inheritance doesn’t apply to Electron — see Guides: Desktop integration for the OAuth-style flow we use for xct-agent-desktop.
Last updated: