SPA vs SSR — entenda a diferença
Uma SPA (Single Page Application) com Vite roda inteiramente no browser. Não há servidor renderizando HTML — o bundle JS é baixado uma vez e tudo acontece no client.
Por isso a session do SuperDB Auth fica em localStorage (padrão), não em cookies httpOnly. Isso é adequado para a maioria dos casos; para SSR use o Quickstart Next.js.
Diferenças chave vs Next.js:
- Sem middleware — proteção de rotas via React Context
- Session em localStorage (persiste ao fechar e reabrir o browser)
- Sem server components — tudo é client-side
- Variáveis de ambiente com prefixo
VITE_(nãoNEXT_PUBLIC_)
Passo a passo
1Criar o projeto Vite
Use o template oficial do Vite para React com TypeScript. O scaffold já inclui hot-reload, aliases e configuração de build otimizado.
npm create vite@latest meu-app -- --template react-ts
cd meu-app
npm install
2Instalar o SDK
O mesmo pacote @superdb/auth-js funciona no Vite sem nenhuma configuração especial.
npm install @superdb/auth-js
3Variáveis de ambiente
No Vite, variáveis expostas ao browser precisam do prefixo VITE_. Crie o arquivo .env na raiz:
Nunca coloque a Service Role Key no .env de uma SPA — ela seria exposta no bundle JS. A anon key é segura para o browser.
VITE_SUPERDB_URL=https://auth.superdb.com.br
VITE_SUPERDB_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
4Criar o cliente
No Vite, use import.meta.env para acessar as variáveis de ambiente (não process.env).
import { createClient } from '@superdb/auth-js'
export const superdb = createClient(
import.meta.env.VITE_SUPERDB_URL,
import.meta.env.VITE_SUPERDB_ANON_KEY
)
5Hook useAuth
Crie um hook customizado que expõe o usuário atual e escuta mudanças de sessão em tempo real (login/logout em outra aba, etc.).
O onAuthStateChange dispara imediatamente com a sessão atual e depois a cada mudança — perfeito para inicializar o estado.
import { useState, useEffect } from 'react'
import { superdb } from '../lib/superdb'
import type { User } from '@superdb/auth-js'
export function useAuth() {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
// Sessão inicial
superdb.auth.getUser().then(({ data }) => {
setUser(data.user)
setLoading(false)
})
// Escuta mudanças de sessão (login/logout em qualquer aba)
const { data: { subscription } } = superdb.auth.onAuthStateChange(
(_event, session) => {
setUser(session?.user ?? null)
setLoading(false)
}
)
return () => subscription.unsubscribe()
}, [])
async function signUp(email: string, password: string) {
const { error } = await superdb.auth.signUp({ email, password })
if (error) throw error
}
async function signIn(email: string, password: string) {
const { error } = await superdb.auth.signInWithPassword({ email, password })
if (error) throw error
}
async function signOut() {
await superdb.auth.signOut()
}
return { user, loading, signUp, signIn, signOut }
}
6Context + proteção de rotas
Envolva o app com um AuthProvider e crie um componente ProtectedRoute para redirecionar usuários não autenticados.
import { createContext, useContext, ReactNode } from 'react'
import { useAuth } from '../hooks/useAuth'
import type { User } from '@superdb/auth-js'
interface AuthContextType {
user: User | null
loading: boolean
signUp: (email: string, password: string) => Promise<void>
signIn: (email: string, password: string) => Promise<void>
signOut: () => Promise<void>
}
const AuthContext = createContext<AuthContextType | null>(null)
export function AuthProvider({ children }: { children: ReactNode }) {
const auth = useAuth()
return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>
}
export function useAuthContext() {
const ctx = useContext(AuthContext)
if (!ctx) throw new Error('useAuthContext deve estar dentro de AuthProvider')
return ctx
}
import { Navigate } from 'react-router-dom'
import { useAuthContext } from '../contexts/AuthContext'
import type { ReactNode } from 'react'
export function ProtectedRoute({ children }: { children: ReactNode }) {
const { user, loading } = useAuthContext()
if (loading) return <div>Carregando...</div>
if (!user) return <Navigate to="/login" replace />
return <>{children}</>
}
7Configurar rotas e rodar
Instale o React Router, configure as rotas e inicie o servidor de desenvolvimento.
npm install react-router-dom
npm run dev
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { AuthProvider } from './contexts/AuthContext'
import { ProtectedRoute } from './components/ProtectedRoute'
import LoginPage from './pages/Login'
import Dashboard from './pages/Dashboard'
export default function App() {
return (
<AuthProvider>
<BrowserRouter>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/dashboard" element={
<ProtectedRoute><Dashboard /></ProtectedRoute>
} />
</Routes>
</BrowserRouter>
</AuthProvider>
)
}
Próximos passos
- Adicionar OAuth com Google
- Configurar Row Level Security
- Migrar para Next.js (SSR + middleware)
- Referência completa do SDK