Skip to content
← Volver al blog Desarrollo Web

Añadiendo Autenticación a SvelteKit con Outseta

Si estás construyendo un producto SaaS con SvelteKit, necesitarás autenticación — y necesitarás que sea más que solo un formulario de inicio de sesión. Necesitas verificación de correo electrónico, restablecimiento de contraseña, gestión de perfil y control de acceso por suscripción. Implementar todo eso por tu cuenta son semanas de trabajo. Outseta te da esas piezas como un servicio integrable, dejándote libre para construir el producto real.

Esta guía recorre los tres pasos que más importan: añadir el script de Outseta, proteger rutas del lado del servidor con verificación JWT, y activar flujos de autenticación desde tus componentes Svelte.

La Configuración del Magic Script

Outseta proporciona un único fragmento de JavaScript — el “Magic Script” — que inicializa su SDK del lado del cliente. Añádelo a tu src/app.html en el <head>, antes de que SvelteKit hidrate la página:

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%sveltekit.assets%/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <!-- Outseta Magic Script -->
    <script src="https://cdn.outseta.com/outseta.min.js"
      data-options='{"domain":"tu-dominio.outseta.com"}'></script>

    %sveltekit.head%
  </head>
  <body data-sveltekit-preload-data="hover">
    <div style="display: contents">%sveltekit.body%</div>
  </body>
</html>

Reemplaza tu-dominio.outseta.com con tu subdominio real de Outseta desde el panel de control.

¿Por qué debe ir en <head> antes de %sveltekit.head%? Porque Outseta inicializa window.Outseta de forma síncrona cuando se ejecuta el script. Si los scripts del head de SvelteKit se ejecutan primero, cualquier componente que llame a window.Outseta.auth.open() al montarse encontrará window.Outseta como undefined. Cargar el script primero garantiza que el SDK esté disponible desde el momento en que tu aplicación se hidrata.

Protegiendo Rutas con Verificación JWT

Outseta emite un token de acceso JWT almacenado en una cookie llamada access-token. En SvelteKit, puedes verificar este token en src/hooks.server.ts y adjuntar el usuario decodificado a event.locals — haciendo que el usuario esté disponible para cada +page.server.ts y +layout.server.ts en el árbol.

Aquí tienes un hooks.server.ts mínimo usando la API REST de Outseta para verificar el token (sin necesidad de gestión de claves asimétricas):

typescript
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
  const token = event.cookies.get('access-token');

  if (token) {
    try {
      // Verificar el token contra el endpoint público de Outseta.
      // Es una llamada ligera — Outseta valida la firma y devuelve los claims.
      const res = await fetch('https://tu-dominio.outseta.com/api/v1/profile', {
        headers: { Authorization: `bearer ${token}` }
      });

      if (res.ok) {
        const profile = await res.json();
        event.locals.user = {
          uid: profile.Uid,
          email: profile.Email,
          firstName: profile.FirstName,
          lastName: profile.LastName,
          accountUid: profile.Account?.Uid ?? null,
          planUid: profile.Account?.CurrentSubscription?.Plan?.Uid ?? null
        };
      }
    } catch {
      // Token inválido o expirado — tratar como no autenticado
    }
  }

  return resolve(event);
};

También querrás declarar la forma del user en App.Locals en src/app.d.ts:

typescript
declare global {
  namespace App {
    interface Locals {
      user?: {
        uid: string;
        email: string;
        firstName: string;
        lastName: string;
        accountUid: string | null;
        planUid: string | null;
      };
    }
  }
}

Una vez que event.locals.user está configurado, puedes proteger cualquier ruta en su +page.server.ts:

typescript
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = ({ locals }) => {
  if (!locals.user) throw redirect(302, '/login');
  return { user: locals.user };
};

Activando el Login desde SvelteKit

El SDK de Outseta expone window.Outseta.auth.open() para abrir el widget de autenticación como popup — sin necesidad de redirección de página. Aquí tienes un componente Svelte mínimo que conecta un botón de “Iniciar sesión”:

svelte
<script lang="ts">
  import { onMount } from 'svelte';

  let user = $state<{ email: string } | null>(null);

  onMount(() => {
    // window.Outseta está disponible aquí porque el Magic Script se cargó primero.
    const outseta = (window as any).Outseta;

    // Leer el estado de autenticación actual
    const profile = outseta.getUser();
    if (profile) user = { email: profile.Email };

    // Escuchar cambios en el estado de autenticación (login, logout, cambio de plan)
    outseta.on('accessToken.set', () => {
      const updated = outseta.getUser();
      user = updated ? { email: updated.Email } : null;
    });
  });

  function openLogin() {
    (window as any).Outseta.auth.open({ widgetMode: 'login' });
  }

  function openSignup() {
    (window as any).Outseta.auth.open({ widgetMode: 'register' });
  }

  function logout() {
    (window as any).Outseta.auth.logout();
  }
</script>

{#if user}
  <span class="text-sm text-gray-600">Sesión iniciada como {user.email}</span>
  <button onclick={logout} class="btn-secondary">Cerrar sesión</button>
{:else}
  <button onclick={openLogin} class="btn-secondary">Iniciar sesión</button>
  <button onclick={openSignup} class="btn-primary">Comenzar</button>
{/if}

El listener outseta.on('accessToken.set', ...) se dispara cada vez que el estado de autenticación cambia — después del login, después del logout y después de un cambio de plan. Este es el lugar correcto para sincronizar tu estado de UI local con la autenticación de Outseta.

Conclusión

Outseta maneja las partes más difíciles de la autenticación SaaS: flujos de verificación de correo electrónico, restablecimiento de contraseña, interfaz de gestión de cuenta y eventos del ciclo de vida de facturación. Al delegar esto a Outseta, evitas mantener un backend de gestión de usuarios por completo.

El patrón de tres piezas descrito arriba — Magic Script en app.html, verificación JWT en hooks.server.ts, y el widget de autenticación activado desde un componente Svelte — te da una capa de autenticación completa y lista para producción con alrededor de 60 líneas de código. Desde ahí puedes añadir control de acceso por suscripción, gestión de pruebas y seguimiento de uso usando el mismo event.locals.user.planUid que el hook ya proporciona.


¿Construyendo algo con SvelteKit y Outseta? Contáctanos — nos encantaría saber en qué estás trabajando.

¿Te gustó este artículo?

Suscríbete a nuestro feed RSS o contáctanos para hablar de tu próximo proyecto.