diff --git a/studio/frontend/src/app/auth-guards.ts b/studio/frontend/src/app/auth-guards.ts new file mode 100644 index 0000000000..83e4e39a32 --- /dev/null +++ b/studio/frontend/src/app/auth-guards.ts @@ -0,0 +1,23 @@ +import { redirect } from "@tanstack/react-router"; +import { + getPostAuthRoute, + hasAuthToken, + hasRefreshToken, + refreshSession, +} from "@/features/auth"; + +async function hasActiveSession(): Promise { + if (hasAuthToken()) return true; + if (!hasRefreshToken()) return false; + return refreshSession(); +} + +export async function requireAuth(): Promise { + if (await hasActiveSession()) return; + throw redirect({ to: "/login" }); +} + +export async function requireGuest(): Promise { + if (!(await hasActiveSession())) return; + throw redirect({ to: getPostAuthRoute() }); +} diff --git a/studio/frontend/src/app/routes/chat.tsx b/studio/frontend/src/app/routes/chat.tsx index 87d1dcd853..d773b74a41 100644 --- a/studio/frontend/src/app/routes/chat.tsx +++ b/studio/frontend/src/app/routes/chat.tsx @@ -1,5 +1,6 @@ import { createRoute } from "@tanstack/react-router"; import { lazy } from "react"; +import { requireAuth } from "../auth-guards"; import { Route as rootRoute } from "./__root"; const ChatPage = lazy(() => @@ -9,5 +10,6 @@ const ChatPage = lazy(() => export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/chat", + beforeLoad: () => requireAuth(), component: ChatPage, }); diff --git a/studio/frontend/src/app/routes/export.tsx b/studio/frontend/src/app/routes/export.tsx index 93bb83cd98..26f047b23d 100644 --- a/studio/frontend/src/app/routes/export.tsx +++ b/studio/frontend/src/app/routes/export.tsx @@ -1,5 +1,6 @@ import { createRoute } from "@tanstack/react-router"; import { lazy } from "react"; +import { requireAuth } from "../auth-guards"; import { Route as rootRoute } from "./__root"; const ExportPage = lazy(() => @@ -11,5 +12,6 @@ const ExportPage = lazy(() => export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/export", + beforeLoad: () => requireAuth(), component: ExportPage, }); diff --git a/studio/frontend/src/app/routes/grid-test.tsx b/studio/frontend/src/app/routes/grid-test.tsx index 6afde70656..dd9113bf28 100644 --- a/studio/frontend/src/app/routes/grid-test.tsx +++ b/studio/frontend/src/app/routes/grid-test.tsx @@ -7,11 +7,13 @@ import { CardTitle, } from "@/components/ui/card"; import { createRoute } from "@tanstack/react-router"; +import { requireAuth } from "../auth-guards"; import { Route as rootRoute } from "./__root"; export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/grid-test", + beforeLoad: () => requireAuth(), component: GridTestPage, }); diff --git a/studio/frontend/src/app/routes/home.tsx b/studio/frontend/src/app/routes/home.tsx index 5903b33295..bf2f3a6b58 100644 --- a/studio/frontend/src/app/routes/home.tsx +++ b/studio/frontend/src/app/routes/home.tsx @@ -1,10 +1,12 @@ import { ComponentExample } from "@/components/component-example"; import { createRoute } from "@tanstack/react-router"; +import { requireAuth } from "../auth-guards"; import { Route as rootRoute } from "./__root"; export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/", + beforeLoad: () => requireAuth(), component: HomePage, }); diff --git a/studio/frontend/src/app/routes/login.tsx b/studio/frontend/src/app/routes/login.tsx index 77e22123d8..5d86484288 100644 --- a/studio/frontend/src/app/routes/login.tsx +++ b/studio/frontend/src/app/routes/login.tsx @@ -1,5 +1,6 @@ import { createRoute } from "@tanstack/react-router"; import { lazy } from "react"; +import { requireGuest } from "../auth-guards"; import { Route as rootRoute } from "./__root"; const LoginPage = lazy(() => @@ -9,5 +10,6 @@ const LoginPage = lazy(() => export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/login", + beforeLoad: () => requireGuest(), component: LoginPage, }); diff --git a/studio/frontend/src/app/routes/onboarding.tsx b/studio/frontend/src/app/routes/onboarding.tsx index e2f9b9db86..664f75249e 100644 --- a/studio/frontend/src/app/routes/onboarding.tsx +++ b/studio/frontend/src/app/routes/onboarding.tsx @@ -1,5 +1,6 @@ import { createRoute } from "@tanstack/react-router"; import { lazy } from "react"; +import { requireAuth } from "../auth-guards"; import { Route as rootRoute } from "./__root"; const WizardLayout = lazy(() => @@ -11,5 +12,6 @@ const WizardLayout = lazy(() => export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/onboarding", + beforeLoad: () => requireAuth(), component: WizardLayout, }); diff --git a/studio/frontend/src/app/routes/signup.tsx b/studio/frontend/src/app/routes/signup.tsx index 154193f9c8..241a8e852a 100644 --- a/studio/frontend/src/app/routes/signup.tsx +++ b/studio/frontend/src/app/routes/signup.tsx @@ -1,5 +1,6 @@ import { createRoute } from "@tanstack/react-router"; import { lazy } from "react"; +import { requireGuest } from "../auth-guards"; import { Route as rootRoute } from "./__root"; const SignupPage = lazy(() => @@ -11,5 +12,6 @@ const SignupPage = lazy(() => export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/signup", + beforeLoad: () => requireGuest(), component: SignupPage, }); diff --git a/studio/frontend/src/app/routes/studio.tsx b/studio/frontend/src/app/routes/studio.tsx index 333bcefdb8..be3a912644 100644 --- a/studio/frontend/src/app/routes/studio.tsx +++ b/studio/frontend/src/app/routes/studio.tsx @@ -1,5 +1,6 @@ import { createRoute } from "@tanstack/react-router"; import { lazy } from "react"; +import { requireAuth } from "../auth-guards"; import { Route as rootRoute } from "./__root"; const StudioPage = lazy(() => @@ -11,5 +12,6 @@ const StudioPage = lazy(() => export const Route = createRoute({ getParentRoute: () => rootRoute, path: "/studio", + beforeLoad: () => requireAuth(), component: StudioPage, }); diff --git a/studio/frontend/src/features/auth/components/auth-form.tsx b/studio/frontend/src/features/auth/components/auth-form.tsx index 588c245285..e8d531c0b4 100644 --- a/studio/frontend/src/features/auth/components/auth-form.tsx +++ b/studio/frontend/src/features/auth/components/auth-form.tsx @@ -33,11 +33,9 @@ type AuthFormProps = { export function AuthForm({ mode }: AuthFormProps): ReactElement | null { const navigate = useNavigate(); const [showPassword, setShowPassword] = useState(false); - const [showConfirmPassword, setShowConfirmPassword] = useState(false); const [username, setUsername] = useState("admin"); const [setupToken, setSetupToken] = useState(""); const [password, setPassword] = useState(""); - const [confirmPassword, setConfirmPassword] = useState(""); const [loading, setLoading] = useState(false); const [statusLoading, setStatusLoading] = useState(true); const [initialized, setInitialized] = useState(null); @@ -106,10 +104,6 @@ export function AuthForm({ mode }: AuthFormProps): ReactElement | null { event.preventDefault(); setError(null); - if (!isLoginMode && password !== confirmPassword) { - setError("Passwords not match."); - return; - } if (!isLoginMode && !setupToken.trim()) { setError("Setup token required."); return; @@ -221,37 +215,6 @@ export function AuthForm({ mode }: AuthFormProps): ReactElement | null { )} - {!isLoginMode && ( -
- -
- setConfirmPassword(event.target.value)} - minLength={8} - required - /> - -
-
- )} - {helperText && (

{helperText}

)} diff --git a/studio/frontend/src/features/auth/index.ts b/studio/frontend/src/features/auth/index.ts index 87ed7e4173..a6651b0c00 100644 --- a/studio/frontend/src/features/auth/index.ts +++ b/studio/frontend/src/features/auth/index.ts @@ -1,3 +1,10 @@ export { LoginPage } from "./login-page"; export { SignupPage } from "./signup-page"; -export { isOnboardingDone, markOnboardingDone } from "./session"; +export { refreshSession } from "./api"; +export { + getPostAuthRoute, + hasAuthToken, + hasRefreshToken, + isOnboardingDone, + markOnboardingDone, +} from "./session";