You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: name the four API/auth hosts and retire the pre-migration pair
The code already resolves the right hosts after the Aug 2026 issuer
migration — `accounts.mukoko.com` for the AuthKit issuer,
`auth.mukoko.com` for the auth API, both allowed in the CSP. CLAUDE.md
and SECURITY.md still named the retired `identity.nyuchi.com` /
`api.identity.nyuchi.com` pair, so the documented setup no longer matched
the shipped one.
Adds a four-host table to CLAUDE.md rather than only correcting the
strings. Two of these have now been confused in practice: an issuer
default pointed at an auth API host, and a platform client default
pointed at `api.mukoko.com` — a separate Mukoko gateway still being
built, which is neither WorkOS nor the gateway serving traffic
(`api.nyuchi.com`). Four adjacent-looking hostnames, four distinct jobs,
and each mix-up fails a long way from its cause: an issuer pointed at an
API host yields metadata that validates but dead-ends at discovery,
before sign-in is ever attempted.
Historical references are kept where they aid recognition — a reader who
finds the old host in a dashboard needs to know it was real and is now
retired, not wonder whether it is a typo.
Docs only; no code paths touched. 887 tests pass, lint clean (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HFaeL83iEL5gqQXhHweH6u
Same-origin fallback endpoints: `events`, `events/[id]` (both also take bearer-authed `POST`/`PATCH` for the MCP), `categories`, `cities`, `community/stats`, `health` (liveness + Mongo dependency probe — `200 ok` / `503 down`, `X-Health-Status` header, `HEAD` for cheap polling; shaped like kweli's `/api/health` so one monitor config covers both, and necessary because every Mongo read degrades to empty rather than throwing, so a `200` on `/` is NOT evidence the app is healthy), `og` (OG image), `media/upload` (WorkOS-gated cover-image upload to R2), `webhooks/workos` (guaranteed user provisioning — see Authentication Flow), and `auth/dev-login` (local dev bypass only). Auth itself is handled by the hosted-AuthKit entry route `/auth/hosted` (redirects to WorkOS) and `/callback` — see the Authentication Flow section.
118
118
119
-
**Agent-readiness discovery** — three `.well-known` route handlers (`src/app/.well-known/*/route.ts`, all `force-dynamic`, `Access-Control-Allow-Origin: *`) advertise the **WorkOS AuthKit OAuth 2.1 authorization server** (`identity.nyuchi.com/oauth2/*`) from the Nhimbe origin so MCP agents/clients can run standard discovery: `oauth-authorization-server` (RFC 8414 — authorize/token/JWKS **plus the DCR `registration_endpoint`**), `oauth-protected-resource` (RFC 9728 — Nhimbe as resource server, pointing at `/auth.md`; its `resource` is derived from the request host so the doc self-identifies correctly whether served on `nhimbe.com` or `events.mukoko.com`), and `openid-configuration` (OIDC Discovery 1.0, RS256). All four surfaces (these three + `/auth.md`) derive their endpoints from the single helper `src/lib/auth/workos-metadata.ts` (`WORKOS_AUTHKIT_DOMAIN`, default `identity.nyuchi.com`) — the AuthKit domain that serves its own self-consistent metadata and DCR. This is deliberately **not** the API domain in the RFC 9728 `authorization_servers` pointer: `api.identity.nyuchi.com` serves no authorization-server metadata (a client following a pointer there 404s and the flow dead-ends). WorkOS remains the real authorization server; these endpoints just advertise it. The bearer-token **verifier** (`workos-token.ts`) independently reads JWKS from the **API** domain (`WORKOS_API_HOSTNAME` → `/sso/jwks/{clientId}`); advertising the AuthKit domain while verifying against the API domain is safe because a WorkOS environment signs every access token with one key, published (identical `kid`) at both hosts, and the verifier pins only signature + expiry + subject.
119
+
**Agent-readiness discovery** — three `.well-known` route handlers (`src/app/.well-known/*/route.ts`, all `force-dynamic`, `Access-Control-Allow-Origin: *`) advertise the **WorkOS AuthKit OAuth 2.1 authorization server** (`accounts.mukoko.com/oauth2/*`) from the Nhimbe origin so MCP agents/clients can run standard discovery: `oauth-authorization-server` (RFC 8414 — authorize/token/JWKS **plus the DCR `registration_endpoint`**), `oauth-protected-resource` (RFC 9728 — Nhimbe as resource server, pointing at `/auth.md`; its `resource` is derived from the request host so the doc self-identifies correctly whether served on `nhimbe.com` or `events.mukoko.com`), and `openid-configuration` (OIDC Discovery 1.0, RS256). All four surfaces (these three + `/auth.md`) derive their endpoints from the single helper `src/lib/auth/workos-metadata.ts` (`WORKOS_AUTHKIT_DOMAIN` / `WORKOS_ISSUER`, default `accounts.mukoko.com`) — the AuthKit domain that serves its own self-consistent metadata and DCR. This is deliberately **not** the API domain in the RFC 9728 `authorization_servers` pointer: `auth.mukoko.com` serves no authorization-server metadata (a client following a pointer there 404s and the flow dead-ends). WorkOS remains the real authorization server; these endpoints just advertise it. The bearer-token **verifier** (`workos-token.ts`) independently reads JWKS from the **API** domain (`WORKOS_API_HOSTNAME` → `/sso/jwks/{clientId}`); advertising the AuthKit domain while verifying against the API domain is safe because a WorkOS environment signs every access token with one key, published (identical `kid`) at both hosts, and the verifier pins only signature + expiry + subject.
@@ -137,7 +137,7 @@ Auth uses **WorkOS's hosted AuthKit UI**. Nhimbe no longer ships a self-hosted s
137
137
-`src/lib/auth/dev.ts` + `/api/auth/dev-login` — local dev auth bypass (kept).
138
138
-`/callback` is the canonical post-auth landing; `/authenticate` is a legacy redirect → `/`.
139
139
140
-
> **WorkOS environment alignment (critical):**`WORKOS_API_KEY`, `WORKOS_CLIENT_ID`, the `api.identity.nyuchi.com` custom **API** domain (`WORKOS_API_HOSTNAME`), and the `identity.nyuchi.com` hosted **AuthKit UI** domain **must all belong to the same WorkOS environment**. Two distinct domains: `api.identity.nyuchi.com` serves the WorkOS API (authorize/token/JWKS — what the SDK and token verifier call), while `identity.nyuchi.com` serves the hosted sign-in UI (configured in the WorkOS dashboard). A key/client-id/domain split across environments makes the hosted redirect succeed but the callback code exchange fail.
140
+
> **WorkOS environment alignment (critical):**`WORKOS_API_KEY`, `WORKOS_CLIENT_ID`, the `auth.mukoko.com` custom **API** domain (`WORKOS_API_HOSTNAME`), and the `accounts.mukoko.com` hosted **AuthKit UI** domain **must all belong to the same WorkOS environment**. Two distinct domains: `auth.mukoko.com` serves the WorkOS API (authorize/token/JWKS — what the SDK and token verifier call), while `accounts.mukoko.com` serves the hosted sign-in UI (configured in the WorkOS dashboard). A key/client-id/domain split across environments makes the hosted redirect succeed but the callback code exchange fail.
141
141
142
142
### AI — Shamwari (`src/lib/ai/`)
143
143
@@ -337,8 +337,19 @@ Set in Vercel (prod + preview) and locally in `.env.local`:
337
337
-`WORKOS_CLIENT_ID` — WorkOS Client ID (server-only; no `NEXT_PUBLIC_` prefix).
338
338
-`WORKOS_API_KEY` — server-only, used by the AuthKit proxy.
-`WORKOS_API_HOSTNAME`*(optional)* — defaults to `api.workos.com`; set to `api.identity.nyuchi.com` (the custom **API** domain) to route WorkOS API calls — and the bearer-token verifier's JWKS fetch (`/sso/jwks/{clientId}`) — through it. This is the API surface, **not** the authorization-server or hosted-UI domain.
341
-
-`WORKOS_AUTHKIT_DOMAIN`*(optional)* — the hosted **AuthKit** domain (`identity.nyuchi.com` in production; default), which is the OAuth 2.1 **authorization server** MCP clients discover and authenticate against (`/oauth2/{authorize,token,register,jwks}`, DCR enabled). Everything the `.well-known/*` discovery routes and `/auth.md` advertise is built from this via `src/lib/auth/workos-metadata.ts`. Override per environment (e.g. a WorkOS-hosted `*.authkit.app` domain).
340
+
-`WORKOS_API_HOSTNAME`*(optional)* — defaults to `api.workos.com`; set to `auth.mukoko.com` (the custom **API** domain) to route WorkOS API calls — and the bearer-token verifier's JWKS fetch (`/sso/jwks/{clientId}`) — through it. This is the API surface, **not** the authorization-server or hosted-UI domain. (Was `api.identity.nyuchi.com` before the Aug 2026 migration.)
341
+
-`WORKOS_AUTHKIT_DOMAIN`*(optional)* — the hosted **AuthKit** domain (`accounts.mukoko.com` in production; the code default), which is the OAuth 2.1 **authorization server** MCP clients discover and authenticate against (`/oauth2/{authorize,token,register,jwks}`, DCR enabled). Everything the `.well-known/*` discovery routes and `/auth.md` advertise is built from this via `src/lib/auth/workos-metadata.ts`. Accepts `WORKOS_ISSUER` as the preferred spelling. Override per environment (e.g. `accounts-staging.mukoko.com`, or a WorkOS-hosted `*.authkit.app` domain). (Was `identity.nyuchi.com` before the Aug 2026 migration.)
342
+
343
+
> **The four hosts, and why they are not interchangeable.** Three `*.mukoko.com` subdomains plus one `nyuchi.com` do four different jobs, and mixing them up fails a long way from the cause:
344
+
>
345
+
> | Host | What it is |
346
+
> | --- | --- |
347
+
> |`accounts.mukoko.com`| WorkOS **AuthKit issuer** — the OAuth 2.1 authorization server agents discover. Serves its own self-consistent metadata + DCR. `WORKOS_AUTHKIT_DOMAIN` / `WORKOS_ISSUER`. |
348
+
> |`auth.mukoko.com`| WorkOS **auth API** — what the SDK calls and where the JWKS fetch goes. `WORKOS_API_HOSTNAME`. |
349
+
> |`api.nyuchi.com`| The **Nyuchi API gateway** (FastAPI on Fly, repo `nyuchi/api-gateway`) — the gateway serving traffic today. Nothing to do with WorkOS. |
350
+
> |`api.mukoko.com`| A **separate Mukoko API gateway still being built** — serves nothing usable yet. Also not WorkOS, despite sitting between the two that are. |
351
+
>
352
+
> Advertising the auth API where the issuer belongs produces metadata that validates but dead-ends: a client following the pointer finds no authorization-server document and the flow dies at discovery, before sign-in.
342
353
-`NEXT_PUBLIC_WORKOS_REDIRECT_URI` — usually `${NEXT_PUBLIC_SITE_URL}/callback`. The `NEXT_PUBLIC_` prefix is **required** — AuthKit reads it from the client bundle to form the OAuth start URL.
343
354
-`WORKOS_WEBHOOK_SECRET` — server-only signing secret for the WorkOS event webhook (`POST /api/webhooks/workos`, guaranteed user provisioning). Create the webhook endpoint `https://nhimbe.com/api/webhooks/workos` in the WorkOS dashboard (user + organization_membership events) and copy its signing secret here. When unset the endpoint answers 503 and provisioning falls back to the callback + lazy sync.
344
355
-`SHAMWARI_AI_GATEWAY_URL`, `SHAMWARI_AI_GATEWAY_TOKEN` — Cloudflare AI Gateway base + provider bearer; optional `SHAMWARI_AI_GATEWAY_AUTH_TOKEN` for the authenticated gateway.
0 commit comments