Docs / Frameworks / Vite + React
Vite + React (browser-only SPA)
A pure SPA can only call flarelink.auth.*. Database and storage need the service key — put those behind your own API (a small Worker, a Vercel function, etc.) and have the SPA call that. Never ship the service key in a Vite bundle (anything in import.meta.env that isn't VITE_-prefixed stays server-side; even so, don't put the key in the SPA).
// src/flarelink.ts
import { createFlarelink } from "@flarelink/client"
export const flarelink = createFlarelink({
url: import.meta.env.VITE_FLARELINK_AUTH_URL,
})
// src/App.tsx
import { useEffect, useState } from "react"
import { flarelink } from "./flarelink"
import type { User } from "@flarelink/client"
export default function App() {
const [me, setMe] = useState<User | null>(null)
useEffect(() => { flarelink.auth.getMe().then(setMe) }, [])
return <div>{me ? `Hi, ${me.name}` : "Signed out"}</div>
}
Protect a route
In a SPA the guard is a client-side gate: call getMe(), show a loader while it resolves, then render or redirect. This is a UX guard, not a security boundary — the real authorization happens server-side in the API the SPA calls.
// src/RequireAuth.tsx
import { useEffect, useState } from "react"
import { Navigate } from "react-router-dom"
import { flarelink } from "./flarelink"
import type { User } from "@flarelink/client"
export function RequireAuth({ children }: { children: React.ReactNode }) {
const [state, setState] = useState<"loading" | User | null>("loading")
useEffect(() => { flarelink.auth.getMe().then(setState).catch(() => setState(null)) }, [])
if (state === "loading") return <p>Loading…</p>
if (!state) return <Navigate to="/login" replace />
return <>{children}</>
}
A client-side guard only hides UI. Your data API must independently call
getMe() (with the cookie forwarded) and scope every query to that user — see Hono / Workers for a matching API.# .env
VITE_FLARELINK_AUTH_URL=https://myapp-auth.your-subdomain.workers.dev
Something unclear or missing? [email protected]
llms-full.txt ↗