O que vamos fazer
- Ligar o Google no painel, sem chave nenhuma (modo gerenciado) ou com o app Google do seu produto.
- Cadastrar a URL para onde o login volta.
- Um botão que chama
db.auth.signInWithOAuth()e abre o Google. - Uma página de volta que troca o
?code=pela sessão comdb.auth.exchangeCodeForSession().
O exemplo é uma SPA em React com Vite. No fim, a mesma receita no celular com Expo.
Como o fluxo funciona
- O botão chama
signInWithOAuth({ provider: 'google', redirectTo }). O SDK gera o par PKCE, guarda o verificador no armazenamento da sessão e devolvedata.url, o endereço do Google. Ele não redireciona sozinho: quem abre a URL é o seu código. - A pessoa escolhe a conta no Google, que devolve para o SuperDB (
https://auth.superdb.com.br/auth/v1/callback/google). - O SuperDB cria ou encontra a conta e manda a pessoa para o seu
redirectTocom um?code=de uso único. - A página de volta chama
exchangeCodeForSession(code). O SDK confere o verificador PKCE, recebe a sessão e a guarda. Pronto:db.from()já consulta como o usuário logado.
Pré-requisitos
- Um projeto no SuperDB, em qualquer plano, e acesso de dono ou admin a ele (para mexer em Autenticação).
@superdb/client0.2.2 ou mais novo, com o cliente criado com oproject:
import { createClient } from '@superdb/client'
export const db = createClient(
import.meta.env.VITE_SUPERDB_URL, // https://auth.superdb.com.br
import.meta.env.VITE_SUPERDB_ANON_KEY,
{ project: import.meta.env.VITE_SUPERDB_PROJECT },
)
Passo 1: ligar o Google no painel
No painel, abra o projeto e vá em Autenticação → Login social (OAuth) → Google. Há dois modos:
| Gerenciado | Credenciais próprias | |
|---|---|---|
| O que configurar | Nada: é só ligar | Client ID e Client Secret do Google Cloud |
| Tela de consentimento | Mostra “SuperDB” | Mostra o nome e o logo do seu app |
| Quando usar | Protótipo, app interno, teste | App que vai para o público |
Para usar credenciais próprias, marque usar minhas próprias credenciais e siga o passo a passo que aparece ao lado, no próprio painel. O essencial:
- No Google Cloud Console, preencha a Tela de permissão OAuth (nome, e-mail de suporte, logo). É ela que o usuário vê ao entrar.
- Em Público, publique o app. Enquanto ele estiver em teste, só entram os e-mails cadastrados como testadores.
- Crie a credencial em Credenciais → Criar credenciais → ID do cliente OAuth → Aplicativo da Web.
- Em URIs de redirecionamento autorizados, cole exatamente
https://auth.superdb.com.br/auth/v1/callback/google. - Copie o Client ID e o Client Secret para o painel do SuperDB e salve.
No Google Console vai o endereço do SuperDB, não o do seu app. O Google devolve sempre para auth.superdb.com.br; o endereço do seu app entra no passo 2. Se inverter, o Google responde redirect_uri_mismatch.
Passo 2: cadastrar a URL de volta
Em Autenticação → URLs de redirecionamento, adicione cada endereço para onde o login pode voltar, e salve:
https://app.exemplo.com.br/auth/callback
http://localhost:5173/auth/callback
A comparação é exata: protocolo, domínio, porta e caminho. Um endereço que não está na lista não recebe o code (é o que impede alguém de usar o seu projeto para mandar o login para um site dele). O erro, nesse caso, é oauth_state_unbound, e a mensagem diz qual endereço faltou cadastrar.
Passo 3: o botão
import { useState } from 'react'
import { db } from './lib/superdb'
export function EntrarComGoogle() {
const [erro, setErro] = useState<string | null>(null)
async function entrar() {
setErro(null)
const { data, error } = await db.auth.signInWithOAuth({
provider: 'google',
redirectTo: `${location.origin}/auth/callback`, // igual ao cadastrado no passo 2
})
if (error) {
return setErro(error.code === 'oauth_not_enabled'
? 'O login com Google não está ligado neste projeto.'
: 'Não deu para abrir o Google agora. Tente de novo.')
}
location.assign(data.url) // o SDK devolve a URL; quem abre é você
}
return (
<>
<button type="button" onClick={entrar}>Entrar com Google</button>
{erro && <p role="alert">{erro}</p>}
</>
)
}
Passo 4: a página de volta
A rota /auth/callback lê o code da URL e troca pela sessão. Ela precisa rodar no mesmo navegador que clicou no botão, porque o verificador PKCE ficou guardado nele.
import { useEffect, useRef, useState } from 'react'
import { db } from './lib/superdb'
export function Callback({ aoEntrar }: { aoEntrar: () => void }) {
const [erro, setErro] = useState<string | null>(null)
const jaTrocou = useRef(false)
useEffect(() => {
// Em desenvolvimento, o StrictMode roda o efeito duas vezes. O code só vale uma:
// a segunda troca falharia e mostraria erro para quem acabou de entrar.
if (jaTrocou.current) return
jaTrocou.current = true
const code = new URLSearchParams(location.search).get('code')
if (!code) return setErro('O login não voltou com o código de acesso.')
db.auth.exchangeCodeForSession(code).then(({ error }) => {
history.replaceState(null, '', location.pathname) // o code já foi usado
if (error) return setErro('O login não foi concluído. Tente entrar de novo.')
aoEntrar()
})
}, [aoEntrar])
if (erro) return <p role="alert">{erro} <button onClick={() => location.assign('/login')}>Voltar para o login</button></p>
return <p>Entrando…</p>
}
A sessão vale 1 hora. Desde a versão 0.3, o SDK renova sozinho um minuto antes de vencer, uma vez só mesmo com várias abas abertas. Numa versão anterior, chame db.auth.refreshSession() antes de vencer, ou use o sessao.ts dos templates oficiais. Detalhes em SDK JS → Auth.
Passo 5: quem entrou
import { db } from './superdb'
export async function usuarioAtual() {
const { data, error } = await db.auth.getUser()
if (error || !data.user) return null
// id, email, display_name (o nome da conta Google), email_verified_at...
return data.user
}
Como o SuperDB cuida da conta:
- Primeiro acesso: a conta é criada com o e-mail e o nome que o Google informou. Se o Google confirma o e-mail, ele já nasce verificado.
- Já existia conta com o mesmo e-mail e o Google confirma o e-mail: o login entra nessa conta, em vez de criar uma segunda.
- As contas aparecem no painel, na lista de Usuários do projeto (pelo card da Visão geral). Dados do seu app, como foto e preferências, ficam numa tabela sua, com RLS por
auth.uid().
No celular, com Expo
O fluxo é o mesmo. A diferença é o endereço de volta: um deep link do app, que também vai em URLs de redirecionamento.
import * as WebBrowser from 'expo-web-browser'
import * as Linking from 'expo-linking'
import { db } from './superdb'
export async function entrarComGoogle() {
const volta = Linking.createURL('auth') // meuapp://auth no app instalado
const { data, error } = await db.auth.signInWithOAuth({ provider: 'google', redirectTo: volta })
if (error) throw new Error(error.message)
const r = await WebBrowser.openAuthSessionAsync(data.url, volta)
if (r.type !== 'success') return null // a pessoa fechou o navegador
const { queryParams } = Linking.parse(r.url) // o URL do React Native não lê a query
const code = typeof queryParams?.code === 'string' ? queryParams.code : null
if (!code) return null
const troca = await db.auth.exchangeCodeForSession(code)
return troca.error ? null : troca.data.session
}
No Expo Go, Linking.createURL('auth') devolve um endereço exp:// com o IP da sua máquina, e ele muda quando a rede muda. Para testar com calma, cadastre o que aparecer no log ou use um development build, que tem o scheme fixo do app. No celular, a sessão precisa de um armazenamento persistente (AsyncStorage): o template Expo já vem assim.
GitHub e Apple
O código é o mesmo; muda o provider. Os dois também têm modo gerenciado, e o painel mostra o passo a passo das credenciais próprias:
await db.auth.signInWithOAuth({ provider: 'github', redirectTo })
await db.auth.signInWithOAuth({ provider: 'apple', redirectTo })
No GitHub, a URL de callback do app é https://auth.superdb.com.br/auth/v1/callback/github. Na Apple, credenciais próprias pedem um Services ID, a chave .p8 e uma conta paga no Apple Developer. Microsoft ainda não é self-serve.
Erros comuns
oauth_state_unbound depois de escolher a conta
O redirectTo não bate com nenhuma URL cadastrada no passo 2. Compare caractere por caractere: localhost e 127.0.0.1 são endereços diferentes, e uma barra no fim também conta.
oauth_not_enabled ao clicar no botão
O Google não está ligado neste projeto. Confira em Autenticação → Login social (OAuth), e se o project do cliente é o projeto certo.
redirect_uri_mismatch na tela do Google
Só acontece com credenciais próprias: falta https://auth.superdb.com.br/auth/v1/callback/google nas URIs autorizadas do Google Cloud Console.
no_pkce_verifier na página de volta
A troca rodou num navegador (ou armazenamento) diferente do que clicou no botão, ou o exchangeCodeForSession foi chamado duas vezes. Refaça o login pelo botão; no React, mantenha a guarda do useRef do passo 4.
Só alguns e-mails conseguem entrar
O app do Google ainda está em modo de teste. Publique-o em Tela de permissão OAuth → Público.