OAuth con Google y GitHub en Supabase
OAuth (Open Authorization) es un protocolo que permite a tus usuarios iniciar sesión usando su cuenta de Google, GitHub u otro proveedor externo, sin tener que crear una contraseña nueva en tu app.
El flujo funciona así: tu app redirige al usuario a Google (o GitHub), el usuario autoriza el acceso, y el proveedor redirige de vuelta a tu app con un código de autorización. Supabase se encarga de intercambiar ese código por una sesión.
Por qué usar OAuth
- Menos fricción: El usuario no tiene que recordar otra contraseña
- Verificación automática: El email ya está verificado por el proveedor
- Datos del perfil: Puedes obtener nombre, foto y email directamente
- Seguridad delegada: Google/GitHub manejan la seguridad de las credenciales
Configurar Google OAuth
Paso 1: Crear credenciales en Google Cloud
- Ve a console.cloud.google.com
- Crea un proyecto nuevo o selecciona uno existente
- Ve a APIs & Services > Credentials
- Haz clic en Create Credentials > OAuth client ID
- Selecciona Web application como tipo
- En Authorized redirect URIs, agrega:
https://<tu-proyecto>.supabase.co/auth/v1/callbackDonde encuentro la redirect URI
En el Dashboard de Supabase: Authentication > Providers > Google. Ahi aparece la Callback URL exacta que debes agregar en Google Cloud.
- Guarda y copia el Client ID y Client Secret
Paso 2: Configurar la pantalla de consentimiento
En Google Cloud, ve a APIs & Services > OAuth consent screen:
- Selecciona External como tipo de usuario
- Llena el nombre de la app, email de soporte y logo
- En Scopes, agrega
emailyprofile - Agrega tu dominio en Authorized domains
- Pública la app (mientras pruebas, puedes dejarla en modo Testing)
Paso 3: Configurar en Supabase
- Ve al Dashboard de Supabase: Authentication > Providers > Google
- Activa el provider
- Pega el Client ID y Client Secret de Google Cloud
- Guarda los cambios
Configurar GitHub OAuth
Paso 1: Crear una OAuth App en GitHub
- Ve a github.com/settings/developers
- Haz clic en New OAuth App
- Llena los campos:
- Application name: El nombre de tu app
- Homepage URL: La URL de tu app (por ejemplo,
https://tudominio.com) - Authorization callback URL:
https://<tu-proyecto>.supabase.co/auth/v1/callback- Haz clic en Register application
- Copia el Client ID
- Genera un Client Secret y copialo
Paso 2: Configurar en Supabase
- Ve al Dashboard de Supabase: Authentication > Providers > GitHub
- Activa el provider
- Pega el Client ID y Client Secret de GitHub
- Guarda los cambios
Implementar signInWithOAuth
Una vez configurados los proveedores, el código es idéntico para cualquiera de ellos:
import { createClient } from '@/lib/supabase/client'
const supabase = createClient()
// Login con Google
async function loginConGoogle() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})
if (error) {
console.error('Error:', error.message)
}
// Si no hay error, el navegador se redirige automaticamente a Google
}
// Login con GitHub
async function loginConGitHub() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})
if (error) {
console.error('Error:', error.message)
}
}redirectTo es importante
La URL en redirectTo es donde Supabase redirige después de que el usuario se autentica con el proveedor. Esta URL debe estar registrada en Authentication > URL Configuration > Redirect URLs en el Dashboard de Supabase.
Solicitar permisos adicionales (scopes)
Por defecto, Supabase pide los scopes minimos (email y profile). Si necesitas acceso adicional:
// Ejemplo: acceso a repos privados de GitHub
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: `${window.location.origin}/auth/callback`,
scopes: 'repo read:user'
}
})
// Ejemplo: acceso al Google Calendar
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${window.location.origin}/auth/callback`,
scopes: 'https://www.googleapis.com/auth/calendar.readonly'
}
})Redirect URLs y callback
Configurar Redirect URLs
En el Dashboard de Supabase: Authentication > URL Configuration:
- Site URL: La URL principal de tu app (ejemplo:
https://tudominio.com) - Redirect URLs: Agrega todas las URLs validas a las que Supabase puede redirigir. Incluye:
http://localhost:3000/auth/callback(desarrollo)https://tudominio.com/auth/callback(producción)
Wildcards
Puedes usar wildcards en las Redirect URLs. Por ejemplo, https://*.tudominio.com/auth/callback permite subdominios. Esto es útil si usas preview deployments en Vercel.
Ruta de callback
Necesitas una ruta en tu app que procese el código de autorización después del redirect:
// app/auth/callback/route.ts
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
const next = searchParams.get('next') ?? '/dashboard'
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
return NextResponse.redirect(`${origin}${next}`)
}
}
return NextResponse.redirect(`${origin}/login?error=oauth`)
}Esta ruta es la misma que usamos para la confirmación de email. Un solo endpoint maneja todos los flujos de auth que usan códigos de autorización.
Obtener datos del perfil del proveedor
Después de que el usuario se autentica con OAuth, sus datos del proveedor están disponibles en user_metadata:
const { data: { user } } = await supabase.auth.getUser()
if (user) {
// Datos comunes en todos los proveedores
console.log('Email:', user.email)
console.log('ID:', user.id)
// Datos especificos del proveedor
const metadata = user.user_metadata
console.log('Nombre:', metadata.full_name || metadata.name)
console.log('Avatar:', metadata.avatar_url || metadata.picture)
console.log('Proveedor:', user.app_metadata.provider)
}Estructura de metadata por proveedor
Google devuelve:
user.user_metadata = {
avatar_url: 'https://lh3.googleusercontent.com/...',
email: 'usuario@gmail.com',
email_verified: true,
full_name: 'Juan Perez',
iss: 'https://accounts.google.com',
name: 'Juan Perez',
picture: 'https://lh3.googleusercontent.com/...',
provider_id: '1234567890',
sub: '1234567890'
}GitHub devuelve:
user.user_metadata = {
avatar_url: 'https://avatars.githubusercontent.com/...',
email: 'usuario@ejemplo.com',
email_verified: true,
full_name: 'juanperez',
name: 'Juan Perez',
preferred_username: 'juanperez',
provider_id: '12345678',
sub: '12345678',
user_name: 'juanperez'
}Componente completo de login social
'use client'
import { createClient } from '@/lib/supabase/client'
export function SocialLogin() {
const supabase = createClient()
const handleOAuthLogin = async (provider: 'google' | 'github') => {
const { error } = await supabase.auth.signInWithOAuth({
provider,
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})
if (error) {
console.error(`Error con ${provider}:`, error.message)
}
}
return (
<div className="space-y-3">
<button
onClick={() => handleOAuthLogin('google')}
className="w-full flex items-center justify-center gap-2
py-2 px-4 border border-gray-600 rounded-md
hover:bg-gray-800 transition-colors"
>
<GoogleIcon />
Continuar con Google
</button>
<button
onClick={() => handleOAuthLogin('github')}
className="w-full flex items-center justify-center gap-2
py-2 px-4 border border-gray-600 rounded-md
hover:bg-gray-800 transition-colors"
>
<GitHubIcon />
Continuar con GitHub
</button>
</div>
)
}
// Componentes de iconos simplificados
function GoogleIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24">
<path fill="currentColor" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" />
<path fill="currentColor" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" />
<path fill="currentColor" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" />
<path fill="currentColor" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" />
</svg>
)
}
function GitHubIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
</svg>
)
}Vincular multiples proveedores a una cuenta
Si un usuario se registra con email y después quiere vincular su cuenta de Google, Supabase maneja esto automáticamente si el email coincide. Puedes configurar este comportamiento en el Dashboard:
Authentication > Providers > Email > Auto-confirm when signing in with OAuth providers with a verified email
Cuando está opción está activada y un usuario hace OAuth con el mismo email que uso para registrarse con contraseña, Supabase vincula ambos métodos de autenticación a la misma cuenta.
Cuidado con la vinculación automática
La vinculación automática por email puede ser un riesgo de seguridad si un proveedor OAuth no verifica emails correctamente. Para la mayoría de apps con Google y GitHub esto es seguro, ya que ambos verifican emails. Evalua el riesgo si agregas proveedores menos conocidos.
Proveedores soportados por Supabase
Además de Google y GitHub, Supabase soporta:
| Proveedor | Provider string |
|---|---|
google | |
| GitHub | github |
| Apple | apple |
| Discord | discord |
| Twitter/X | twitter |
facebook | |
| Azure (Microsoft) | azure |
| GitLab | gitlab |
| Bitbucket | bitbucket |
| Slack | slack |
| Spotify | spotify |
| Twitch | twitch |
| LinkedIn (OIDC) | linkedin_oidc |
La configuración sigue el mismo patrón para todos: crear credenciales en el proveedor, agregar la callback URL de Supabase, y pegar Client ID + Client Secret en el Dashboard.