O que vamos fazer
Ao fim deste cookbook, seu app Next.js 15 terá:
- Um botão "Entrar com Google" que redireciona pro consentimento do Google
- Callback handler que troca o
codepor uma sessão SuperDB - Sessão persistente via cookie httpOnly (server e client com acesso)
- Usuário salvo automaticamente em
auth.users(e empublic.profilesvia trigger, se quiser) - Server component que lê o usuário autenticado via
db.auth.getUser()
Pré-requisitos
- Conta SuperDB no plano Pro+ (OAuth está liberado também no Free, mas Pro libera mais redirect URIs)
- Console Google Cloud com um OAuth 2.0 Client ID criado (tipo "Web application")
- Next.js 15 com App Router
- Pacote instalado:
npm install @superdb/supabase-compat
Variáveis de ambiente em .env.local:
NEXT_PUBLIC_SUPERDB_URL=https://api.superdb.com.br
NEXT_PUBLIC_SUPERDB_ANON_KEY=eyJhbGciOi...
Passo 1 — Configurar OAuth no Google Console
- Crie um projeto (ou use existente)
- Vá em APIs & Services → Credentials
- Clique Create Credentials → OAuth client ID
- Application type: Web application
- Em Authorized redirect URIs, adicione:
https://api.superdb.com.br/auth/v1/callback
http://localhost:9999/callback
O primeiro é o callback do SuperDB (produção). O segundo só é necessário se você for testar self-host local. Copie Client ID e Client Secret — você vai colar no próximo passo.
Atenção: a URL acima precisa bater exatamente com o que está no Console — Google compara byte a byte. Trailing slash, http vs https, porta — qualquer diferença e o redirect falha com redirect_uri_mismatch.
Passo 2 — Configurar provider no Dashboard
No Dashboard SuperDB do seu projeto:
- Vá em Auth → Providers
- Clique em Google
- Toggle Enabled
- Cole o Client ID e o Client Secret do passo anterior
- Salve
Dica: o Dashboard mostra a redirect URI exata que você precisa colar no Google Console — copie de lá em vez de digitar. Evita o erro mais comum.
Passo 3 — Botão de login no frontend
Crie um client component com o botão. Use signInWithOAuth passando o provider:
'use client'
import { createBrowserClient } from '@superdb/supabase-compat'
export function GoogleButton() {
const db = createBrowserClient(
process.env.NEXT_PUBLIC_SUPERDB_URL!,
process.env.NEXT_PUBLIC_SUPERDB_ANON_KEY!
)
async function entrar() {
await db.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${location.origin}/auth/callback`,
},
})
}
return <button onClick={entrar}>Entrar com Google</button>
}
'use client'
import { createBrowserClient } from '@superdb/supabase-compat'
export function GoogleButton() {
const db = createBrowserClient(
process.env.NEXT_PUBLIC_SUPERDB_URL,
process.env.NEXT_PUBLIC_SUPERDB_ANON_KEY
)
async function entrar() {
await db.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: `${location.origin}/auth/callback` },
})
}
return <button onClick={entrar}>Entrar com Google</button>
}
curl -X POST "$SUPERDB_URL/auth/v1/authorize?provider=google&redirect_to=http://localhost:3000/auth/callback" \
-H "apikey: $ANON_KEY"
Clicar no botão dispara um redirect 302 do SuperDB pro Google. O usuário consente, Google manda de volta com ?code=... pra /auth/callback.
Passo 4 — Callback handler
Crie a rota que troca o code por sessão e seta o cookie:
import { NextResponse } from 'next/server'
import { createServerClient } from '@superdb/supabase-compat/ssr'
import { cookies } from 'next/headers'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
const next = searchParams.get('next') ?? '/'
if (code) {
const cookieStore = await cookies()
const db = createServerClient(
process.env.NEXT_PUBLIC_SUPERDB_URL!,
process.env.NEXT_PUBLIC_SUPERDB_ANON_KEY!,
{
cookies: {
getAll: () => cookieStore.getAll(),
setAll: (all) => all.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)),
},
}
)
const { error } = await db.auth.exchangeCodeForSession(code)
if (!error) return NextResponse.redirect(`${origin}${next}`)
}
return NextResponse.redirect(`${origin}/login?erro=oauth`)
}
Passo 5 — Ler o usuário no server
Em qualquer server component ou middleware, recupere o usuário autenticado:
import { createServerClient } from '@superdb/supabase-compat/ssr'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
export default async function PerfilPage() {
const cookieStore = await cookies()
const db = createServerClient(
process.env.NEXT_PUBLIC_SUPERDB_URL!,
process.env.NEXT_PUBLIC_SUPERDB_ANON_KEY!,
{ cookies: { getAll: () => cookieStore.getAll(), setAll: () => {} } }
)
const { data: { user } } = await db.auth.getUser()
if (!user) redirect('/login')
return <div>Olá, {user.email}</div>
}
Resultado
Você tem um fluxo OAuth completo. Usuário clica, escolhe a conta Google, volta logado. Da próxima vez que abrir o app, a sessão é restaurada do cookie automaticamente — sem novo redirect.
Variações
Trocar por GitHub
Mesma receita, só muda o provider. Repita o passo 1 no GitHub Developers e troque a string:
- provider: 'google',
+ provider: 'github',
Apple Sign-In
Idem. Precisa de Apple Developer Account ($99/ano), mas o código do app é igual:
await db.auth.signInWithOAuth({
provider: 'apple',
options: { redirectTo: `${location.origin}/auth/callback` },
})
Dropdown com múltiplos providers
Refatore o botão pra receber o provider como prop:
'use client'
import { createBrowserClient } from '@superdb/supabase-compat'
const PROVIDERS = ['google', 'github', 'apple'] as const
export function OAuthButtons() {
const db = createBrowserClient(
process.env.NEXT_PUBLIC_SUPERDB_URL!,
process.env.NEXT_PUBLIC_SUPERDB_ANON_KEY!
)
return PROVIDERS.map((p) => (
<button key={p} onClick={() => db.auth.signInWithOAuth({
provider: p,
options: { redirectTo: `${location.origin}/auth/callback` }
})}>Entrar com {p}</button>
))
}
Erros comuns
redirect_uri_mismatch
A URL no Console Google não bate com a do SuperDB. Solução: copie a redirect URI do Dashboard SuperDB e cole exatamente no Console — não digite.
Cookie não é setado depois do callback
Causa comum: chamando createServerClient sem repassar setAll dos cookies. O exchangeCodeForSession retorna a sessão, mas se você não escrever no cookieStore o Next.js não persiste. Confira o passo 4: o setAll precisa estar implementado.
Tentar usar a sessão antes de trocar o code
Se você fizer db.auth.getUser() no /auth/callback antes do exchangeCodeForSession rodar, vai retornar null — o code ainda não virou sessão. Sempre troque primeiro, depois redirect, e leia o user na página de destino.
Dúvida frequente: a sessão expira em 1h por padrão, mas o refresh token vale 30 dias e o SDK renova automaticamente. Você não precisa lidar com isso na mão.