Codea Bien Logo
Auth sin dolor: Autenticación completa con Supabase
Supabase

Auth sin dolor: Autenticación completa con Supabase

Kevin Dávila

supabase authautenticaciónoauthloginmfa

Confesión: odio configurar autenticación. Los redirects de OAuth, los JWT que expiran justo cuando no deben, las sesiones que se pierden entre pestañas y ese bug de login que solo aparece un domingo a media noche.

Por eso no lo podía creer cuando con Supabase Auth tuve login con Google, GitHub y email/password funcionando en literalmente 15 líneas de código. Aquí vas a armar autenticación completa, de lo básico hasta MFA, sin drama.

El stack de Auth de Supabase

Supabase usa GoTrue como servicio de autenticación. Esto es lo que ofrece:

  • Email/Password

  • OAuth social (Google, GitHub, Apple, Discord, etc.)

  • Magic Link (login sin contraseña)

  • Phone/SMS

  • MFA (Multi-Factor Authentication)

Todo esto viene incluido en el free tier, con hasta 50,000 usuarios.

Configuración inicial

Variables de entorno

// .env
VITE_SUPABASE_URL=https://tu-proyecto.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Cliente de Supabase

// src/lib/supabase.ts
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseKey)

Email y Password

Registro

// src/auth/signup.ts
import { supabase } from '../lib/supabase'

export async function signUp(email: string, password: string) {
  const { data, error } = await supabase.auth.signUp({
    email,
    password,
  })

  if (error) throw error
  return data
}

Login

// src/auth/login.ts
import { supabase } from '../lib/supabase'

export async function signIn(email: string, password: string) {
  const { data, error } = await supabase.auth.signInWithPassword({
    email,
    password,
  })

  if (error) throw error
  return data
}

Logout

// src/auth/logout.ts
import { supabase } from '../lib/supabase'

export async function signOut() {
  const { error } = await supabase.auth.signOut()
  if (error) throw error
}

OAuth Social

Configurar login con Google o GitHub es trivial. Solo necesitas agregar las credenciales OAuth en el dashboard de Supabase.

Google

// src/auth/google.ts
import { supabase } from '../lib/supabase'

export async function signInWithGoogle() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'google',
    options: {
      redirectTo: `${window.location.origin}/auth/callback`
    }
  })

  if (error) throw error
  return data
}

GitHub

// src/auth/github.ts
import { supabase } from '../lib/supabase'

export async function signInWithGitHub() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'github',
    options: {
      redirectTo: `${window.location.origin}/auth/callback`
    }
  })

  if (error) throw error
  return data
}

Configurar OAuth providers

En el dashboard de Supabase:

  1. Ve a Authentication > Providers

  2. Selecciona Google o GitHub

  3. Agrega tu Client ID y Client Secret

  4. Copia la URL de callback que te da Supabase

  5. Configura esa URL en la consola del proveedor (Google Cloud Console, GitHub Settings)

Magic Link

Login sin contraseña, solo con un link al email:

// src/auth/magic-link.ts
import { supabase } from '../lib/supabase'

export async function signInWithMagicLink(email: string) {
  const { data, error } = await supabase.auth.signInWithOtp({
    email,
    options: {
      emailRedirectTo: `${window.location.origin}/auth/callback`
    }
  })

  if (error) throw error
  return data
}

Escuchar cambios de sesión

// src/auth/listener.ts
import { supabase } from '../lib/supabase'

// Escuchar cambios de auth (login, logout, token refresh)
supabase.auth.onAuthStateChange((event, session) => {
  console.log('Auth event:', event)
  console.log('User:', session?.user)
  
  // Eventos posibles:
  // - SIGNED_IN
  // - SIGNED_OUT
  // - TOKEN_REFRESHED
  // - USER_UPDATED
  // - PASSWORD_RECOVERY
})

Obtener el usuario actual

// src/auth/user.ts
import { supabase } from '../lib/supabase'

export async function getCurrentUser() {
  const { data: { user }, error } = await supabase.auth.getUser()
  
  if (error) throw error
  return user
}

MFA (Multi-Factor Authentication)

Para apps que necesitan seguridad extra, Supabase soporta TOTP (Time-based One-Time Password):

// src/auth/mfa.ts
import { supabase } from '../lib/supabase'

// Enroll MFA
export async function enrollMFA() {
  const { data, error } = await supabase.auth.mfa.enroll({
    factorType: 'totp',
    friendlyName: 'Mi App'
  })

  if (error) throw error
  
  // data.totp.qr_code - QR para escanear con app authenticator
  // data.totp.secret - Secret para ingresar manualmente
  return data
}

// Verify MFA
export async function verifyMFA(factorId: string, challengeId: string, code: string) {
  const { data, error } = await supabase.auth.mfa.verify({
    factorId,
    challengeId,
    code
  })

  if (error) throw error
  return data
}

Proteger rutas en el cliente

Con vanilla JS

// src/auth/guard.ts
import { supabase } from '../lib/supabase'

export async function requireAuth() {
  const { data: { session } } = await supabase.auth.getSession()
  
  if (!session) {
    window.location.href = '/login'
    return null
  }
  
  return session
}

Con Angular

// src/app/guards/auth.guard.ts
import { inject } from '@angular/core'
import { CanActivateFn, Router } from '@angular/router'
import { SupabaseService } from '../services/supabase.service'

export const authGuard: CanActivateFn = async () => {
  const supabase = inject(SupabaseService)
  const router = inject(Router)
  
  const { data: { session } } = await supabase.client.auth.getSession()
  
  if (!session) {
    router.navigate(['/login'])
    return false
  }
  
  return true
}

Configuración en el Dashboard

Algunas configuraciones importantes en Authentication > Settings:

  • Site URL: URL de tu app (ej: http://localhost:5173)

  • Redirect URLs: URLs permitidas después del login

  • Email confirmations: Habilitar/deshabilitar confirmación por email

  • Password requirements: Longitud mínima, caracteres especiales

Errores comunes

"Invalid login credentials"

  • Verifica que el usuario exista

  • Revisa que el email esté confirmado (si tienes confirmación habilitada)

"Redirect URL not allowed"

  • Agrega la URL en Authentication > URL Configuration

  • Incluye tanto localhost como tu dominio de producción

Token expirado

  • Supabase maneja refresh tokens automáticamente

  • Verifica que autoRefreshToken esté habilitado (viene por defecto)

Qué sigue

En el próximo artículo vamos con RLS (Row Level Security): cómo proteger tus datos directamente en la base de datos, sin depender solo del código del cliente. Es la pieza que hace que Supabase sea seguro para producción.