mirror of
https://github.com/hanzoai/id.git
synced 2026-10-16 18:38:15 +00:00
55bd028596d2d5ce1d24431665cfb97ee22e23c6
pkgs/auth/src/ui/ProviderButtons.tsx declared its own provider map:
google: { label: 'Continue with Google', brand: 'google' },
github: { label: 'Continue with GitHub', brand: 'github' },
Two providers, where SocialButtons renders four (ORDER = github, gitlab,
google, web3). It was imported by nobody, absent from pkgs/auth/src/ui/index.ts
and therefore never part of the package's public API, and unreferenced across
every repo in the estate. It could not render, so it could not be wrong in
production — it could only be COPIED, and the copy would be missing GitLab and
Wallet from the day it was made.
Login.tsx, Signup.tsx and DeviceApproval.tsx all use SocialButtons, which is
the correct design and stays: it resolves {application, providers} from IAM at
runtime and intersects with PROVIDER_META, so the buttons follow the
application's configuration rather than a hardcoded list.
social.ts is NOT a third list and is untouched: its provider map holds OAuth
authorize ENDPOINTS for buildProviderAuthUrl (11 call sites), which is where to
send the user, not what to show them. All six of its exports are live.
NOTE, and this commit does not fix it: the live asymmetry is IAM
per-application config, not this file. Measured against production in one
browser context —
page GitHub GitLab Google Wallet
sign-in y y y n
sign-up via client_id=hanzo-app y y y y
sign-up direct at hanzo.id/signup y n y y
GitLab is enabled on the hanzo-app application and not on the portal default,
and Wallet renders only under the signup intent. Both are configuration, and
both need a decision about what the canonical provider set is per application.
Co-authored-by: Hanzo Dev <[email protected]>
@hanzo/id
White-label login + identity verification portal. One Vite SPA, four hosts
(hanzo.id, lux.id, zoo.id, pars.id), per-tenant brand resolved from
the request hostname at runtime.
Layout
apps/
web/ Vite + React 19 + @hanzo/gui — the actual SPA
k8s/ Deployment + Service + Ingress (4 hosts, 4 TLS secrets)
pkgs/
shared/ @hanzo/id-shared — TenantConfig + brand resolver
auth/ @hanzo/id-auth — composable login/signup/OTP flows
on top of @hanzo/iam SDK
idv/ @hanzo/id-idv — pluggable identity verification
(Persona, Onfido, Veriff, stub)
legacy-nextjs/ Frozen — predecessor Next.js implementation. Kept
for reference until v0.1.0 ships to production.
Local dev
pnpm install
pnpm dev # http://localhost:5173 (defaults to hanzo brand)
To preview a different brand locally, edit /etc/hosts:
127.0.0.1 lux.id zoo.id pars.id
then visit http://lux.id:5173.
Build
pnpm build # builds apps/web -> dist/
docker build -t ghcr.io/hanzoai/id:0.1.0 .
Adding a brand
- Publish or workspace-link the new per-org brand pkg (must ship
brand.jsonat the package root and match theBrandContractshape inpkgs/shared/src/types.ts). - Add a
DEFAULT_TENANTSentry inpkgs/shared/src/tenant.tsOR put the override in the runtime catalog (IAM_TENANT_CONFIG_JSONenv) so no rebuild is needed. - Add the hostname to
apps/web/vite.config.ts::BRAND_PACKAGES(lets dev + build serve/brand/<pkg>/brand.json). - Add the hostname + TLS secret to
apps/web/k8s/ingress.yaml. - DNS: CNAME or A record → cluster ingress IP.
That's it — no per-brand Worker, no per-brand image, no per-brand deployment. One binary, four brands.
Plugging an IDV provider
import { registerProvider, createPersonaProvider } from '@hanzo/id-idv'
registerProvider(createPersonaProvider({
templateId: import.meta.env.VITE_PERSONA_TEMPLATE_ID,
apiKey: import.meta.env.VITE_PERSONA_API_KEY,
environment: 'production',
}))
The portal stays unchanged — switching providers is a single registration call at boot.
Languages
TypeScript
92.1%
CSS
4.5%
JavaScript
2.6%
Dockerfile
0.6%
HTML
0.2%