MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / AuthGate

Function AuthGate

apps/cloud/src/routes/__root.tsx:216–350  ·  view source on GitHub ↗
({ ssrOrigin }: { ssrOrigin: string | null })

Source from the content-addressed store, hash-verified

214}
215
216function AuthGate({ ssrOrigin }: { ssrOrigin: string | null }) {
217 const auth = useAuth();
218 const location = useLocation();
219 const navigate = useNavigate();
220 const isOnboardingRoute = ONBOARDING_PATHS.has(location.pathname);
221 const isPublicRoute = PUBLIC_PATHS.has(location.pathname);
222 // The org the URL names (the `{-$orgSlug}` segment), if any. `/account/me`
223 // is scoped to it, so `auth.organization` IS this org when the caller is a
224 // member — and `null` when the URL names an org they can't access.
225 const urlOrgSlug = (useParams({ strict: false }) as { orgSlug?: string }).orgSlug;
226 // The same slug derived from the PATHNAME instead of the route params: the
227 // params resolve asynchronously (a fresh load renders once with no orgSlug,
228 // then again with it), and anything keyed on them remounts on that flap.
229 // The pathname is synchronously correct on the very first render, and it is
230 // exactly what the request header derives from (getActiveOrgSlug), so the
231 // registry scope below can never disagree with the header scope.
232 const firstSegment = location.pathname.split("/")[1] ?? "";
233 const pathnameOrgSlug = isValidOrgSlug(firstSegment) ? firstSegment : null;
234
235 // The SSR gate already bounced fresh org-less document requests to
236 // /create-org; this catches the MID-SESSION transitions (org deleted,
237 // membership revoked → /account/me now reports no org). Only for BARE paths:
238 // an org-less result on a slugged URL is a wrong address (404 below), not a
239 // reason to send the user to onboarding.
240 const needsOrgRedirect =
241 auth.status === "authenticated" &&
242 auth.organization == null &&
243 !urlOrgSlug &&
244 !isOnboardingRoute &&
245 !isPublicRoute;
246
247 React.useEffect(() => {
248 if (needsOrgRedirect) {
249 void navigate({ to: "/create-org", replace: true });
250 }
251 }, [needsOrgRedirect, navigate]);
252
253 // The signed-out safety net behind the SSR gate: if a session dies while
254 // the SPA is already loaded (logout elsewhere, expiry), go to /login the
255 // same way a fresh document request would — keeping where they were.
256 const needsLoginRedirect = auth.status === "unauthenticated" && !isPublicRoute;
257 React.useEffect(() => {
258 if (needsLoginRedirect) {
259 window.location.assign(loginPath(`${location.pathname}${location.searchStr}`));
260 }
261 }, [needsLoginRedirect, location.pathname, location.searchStr]);
262
263 if (isPublicRoute) {
264 return <Outlet />;
265 }
266
267 // Every state that isn't "authenticated with an org, on a page that wants
268 // the shell" is a moment between redirects or an edge the gates make
269 // near-impossible (a verified user whose hint hasn't seeded yet). Neutral
270 // blank — the one placeholder that's correct whatever happens next. The
271 // app-shell skeleton this file used to render here is exactly the
272 // wrong-UI flash the SSR gate + hint exist to prevent.
273 if (auth.status === "loading" || auth.status === "unauthenticated") {

Callers

nothing calls this directly

Calls 3

useAuthFunction · 0.90
isValidOrgSlugFunction · 0.90
loginPathFunction · 0.90

Tested by

no test coverage detected