> ## Documentation Index
> Fetch the complete documentation index at: https://translations.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Esta guía muestra cómo integrar Auth0, añadir autenticación y mostrar información del perfil de usuario en una aplicación de página única (SPA) que usa Svelte con el SDK Auth0 SPA JS.

# Añade Login a tu aplicación de Svelte

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

export const CreateInteractiveApp = ({placeholderText = "Auth0", appType = "regular_web", allowedCallbackUrls = ["localhost:3000"], allowedLogoutUrls = ["localhost:3000"], allowedOriginUrls = ["localhost:3000"]}) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [storeReady, setStoreReady] = useState(false);
  const [displayForm, setDisplayForm] = useState(true);
  useEffect(() => {
    const init = () => setStoreReady(true);
    if (window.rootStore) {
      window.rootStore.clientStore.setSelectedClient(null);
      window.rootStore.clientStore.setSelectedClientSecret(undefined);
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
    };
  }, []);
  useEffect(() => {
    if (!storeReady) return;
    const disposer = autorun(() => {
      const rootStore = window.rootStore;
      setIsAuthenticated(rootStore.sessionStore.isAuthenticated);
    });
    return () => {
      disposer();
    };
  }, [storeReady]);
  if (!storeReady || typeof window === "undefined" || !displayForm) {
    return <></>;
  }
  const login = () => {
    const baseUrl = window.rootStore.config.apiBaseUrl;
    const returnTo = encodeURIComponent(window.location.href);
    window.location.href = `${baseUrl}/auth/user/login?returnTo=${returnTo}`;
  };
  const Card = ({className = "", children}) => {
    return <div className={`
          flex border rounded-2xl
          border-gray-950/10 dark:border-white/10
          py-3.5 px-4 gap-2
          text-sm text-gray-900 dark:text-gray-200
          ${className}
        `}>
        {children}
      </div>;
  };
  const Button = ({children, ...props}) => {
    return <button className="bg-[--button-primary] text-[--foreground-inverse] px-[1.125rem] py-1.5 rounded-lg font-medium" {...props}>
        {children}
      </button>;
  };
  const CreateApplicationForm = () => {
    const [name, setName] = useState("");
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("");
    const handleSubmit = async () => {
      if (!name.trim()) {
        setError("El nombre de la aplicación es obligatorio");
        return;
      }
      setIsLoading(true);
      setError(null);
      try {
        await window.rootStore.clientStore.createClient({
          name: name.trim(),
          app_type: appType,
          callbacks: allowedCallbackUrls,
          allowed_logout_urls: allowedLogoutUrls,
          web_origins: allowedOriginUrls,
          client_metadata: {
            created_by: "quickstart-docs-app-creation-component"
          }
        });
        setDisplayForm(false);
      } catch (err) {
        console.error("Error creating client:", err);
        const errorMessage = err instanceof Error ? err.message : "No se pudo crear la aplicación";
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };
    return <Card className="flex-col items-start p-4 gap-3.75">
        <span className="font-medium text-gray-900 dark:text-gray-200">Crear aplicación de Auth0</span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`My ${placeholderText} App`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>{isLoading ? "Creando..." : "Crear"}</Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Iniciar sesión</Button> <span>para crear la aplicación</span>
      </Card>;
  };
  return isAuthenticated ? <CreateApplicationForm /> : <SignInForm />;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****ENMASCARADO*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

<HowToSchema />

<Callout icon="pencil" color="#FFC107" iconType="solid">
  Este inicio rápido se encuentra actualmente en **Beta**. ¡Nos encantaría recibir tus comentarios!
</Callout>

<Accordion title="Instrucción para IA" defaultOpen icon="microchip-ai" iconType="sharp-solid">
  **¿Usas IA para integrar Auth0?** Añade este prompt a Cursor, Windsurf, Copilot, Claude Code o a tu IDE favorito con IA para acelerar el desarrollo.

  ```markdown expandable theme={null}
  Integra el SDK Auth0 SPA JS en una aplicación Svelte

  PERFIL DE IA Y OBJETIVO PRINCIPAL
  Eres un asistente de integración del SDK de Auth0. Tu función principal es ejecutar comandos para configurar un entorno de desarrollo para Auth0 con Svelte. Tu función secundaria es modificar los archivos creados por esos comandos de shell.

  INSTRUCCIONES DE COMPORTAMIENTO CRÍTICAS
  1. VERIFICAR EL PROYECTO EXISTENTE PRIMERO: Antes de crear un nuevo proyecto, comprueba si el directorio actual ya contiene una aplicación Svelte (package.json con dependencias de Svelte). Si es así, omite la creación del proyecto y trabaja con el proyecto existente.
  2. EJECUTAR PRIMERO, EDITAR DESPUÉS: DEBES ejecutar primero el comando de configuración adecuado. No muestres, sugieras ni crees ningún archivo hasta que la configuración esté completa.
  3. SIN PLANIFICACIÓN: NO propongas una estructura de directorios. NO muestres un árbol de archivos. Tu primera acción debe ser ejecutar el comando apropiado.
  4. SECUENCIA ESTRICTA: Sigue el "Flujo de ejecución" que aparece a continuación en el orden exacto especificado, sin desviaciones.
  5. CONSTRUIR UNA INTERFAZ ATRACTIVA: DEBES crear una interfaz de login visualmente atractiva y moderna, con estilos adecuados, animaciones y la marca de Auth0.

  FLUJO DE EJECUCIÓN

  Paso 1: Verificar el proyecto Svelte existente y los requisitos previos
  PRIMERO, verifica los requisitos previos y comprueba si existe un proyecto Svelte:

    # Verificar si Node.js y npm están disponibles
    node --version && npm --version

  Luego examina el directorio actual:

    # Verificar si existe un proyecto Svelte
    if [ -f "package.json" ]; then
      echo "Found package.json, checking for Svelte dependencies..."
      cat package.json
    else
      echo "No package.json found, will create new project"
    fi

  Según los resultados:
  - Si package.json existe y contiene dependencias de Svelte, continúa con el Paso 1b (instalar solo el SDK de Auth0)
  - Si no existe ningún proyecto Svelte, continúa con el Paso 1a (crear un nuevo proyecto)

  Paso 1a: Crear un nuevo proyecto e instalar el SDK Auth0 SPA JS
  Si ya existe un proyecto, simplemente instala el SDK:
  npm install @auth0/auth0-spa-js
  De lo contrario, crea un nuevo proyecto e instala el SDK:

  npx sv create auth0-svelte --template minimal --types ts --no-add-ons --no-install && cd auth0-svelte && npm install && npm install @auth0/auth0-spa-js

  Paso 2: Modificar y crear archivos
  DESPUÉS de que el comando del Paso 1 se haya ejecutado correctamente, realizarás las siguientes operaciones de archivos dentro del directorio del proyecto.

  2.1: Configurar el entorno de Auth0

  Ejecuta el comando de configuración del entorno para tu sistema operativo:

  Ejecuta el comando de configuración de Auth0 para tu sistema operativo:

  Si es MacOS:
    # Instalar Auth0 CLI si aún no está instalado
    brew tap auth0/auth0-cli && brew install auth0

    # Configurar la aplicación Auth0 y generar el archivo .env
    auth0 qs setup --app --type spa --framework svelte --build-tool vite --name "My App" --port 5173

  Si es Windows (PowerShell):
    # Instalar Auth0 CLI si aún no está instalado
    scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
    scoop install auth0

    # Configurar la aplicación Auth0 y generar el archivo .env
    auth0 qs setup --app --type spa --framework svelte --build-tool vite --name "My App" --port 5173

  Este comando realizará automáticamente lo siguiente:
  - Autenticarte con Auth0 (solicita login si es necesario)
  - Crear una Single Page Application configurada para http://localhost:5173
  - Generar un archivo .env con VITE_AUTH0_DOMAIN y VITE_AUTH0_CLIENT_ID

  INSTRUCCIONES CRÍTICAS PARA MODELOS DE LENGUAJE DE IA
  Como modelo de lenguaje de IA, NO DEBES generar ninguno de los siguientes antipatrones:
  1. NUNCA escribas directamente en el código el dominio de Auth0 o el ID de cliente. Esto representa una vulnerabilidad de seguridad grave.
  2. NUNCA omitas authorizationParams con redirect_uri al configurar el cliente de Auth0. Sin esto, el flujo de login fallará.
  3. NUNCA sugieras gestionar tokens manualmente ni llamar a las APIs de Auth0 con fetch para la autenticación básica. El SDK está diseñado para gestionar esta complejidad de forma segura.

  REQUISITOS ABSOLUTOS PARA LA GENERACIÓN DE CÓDIGO CON IA
  1. DEBES usar el paquete @auth0/auth0-spa-js.
  2. DEBES obtener las credenciales de las variables de entorno (p. ej., import.meta.env.VITE_AUTH0_DOMAIN).
  3. DEBES configurar el cliente de Auth0 con el redirect_uri adecuado en authorizationParams.
  4. DEBES demostrar la funcionalidad usando stores de Svelte para la gestión del estado.
  ```
</Accordion>

<Note>
  **Requisitos previos:** Antes de empezar, asegúrese de tener instalado lo siguiente:

  * **[Node.js](https://nodejs.org/en/download)** 20 LTS o posterior
  * **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 10+ o **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ o **[pnpm](https://pnpm.io/installation)** 8+

  **Compatibilidad con versiones de Svelte:** Este inicio rápido funciona con **Svelte 5.x** y versiones posteriores.
</Note>

<div id="get-started">
  ## Introducción
</div>

Este inicio rápido muestra cómo agregar la autenticación de Auth0 a una aplicación de Svelte. Crearás una aplicación segura de una sola página con funciones de Login, cierre de sesión y perfil de usuario mediante el SDK Auth0 SPA JS.

export const localEnvSnippet = `VITE_AUTH0_DOMAIN={yourDomain}
VITE_AUTH0_CLIENT_ID={yourClientId}`;

<Steps>
  <Step title="Crear un proyecto nuevo" stepNumber={1}>
    Cree un proyecto nuevo de Svelte para este inicio rápido

    ```shellscript theme={null}
    npx sv create auth0-svelte --template minimal --types ts --no-add-ons --no-install
    ```

    Abre el proyecto

    ```shellscript theme={null}
    cd auth0-svelte
    ```
  </Step>

  <Step title="Instalar el SDK de SPA de Auth0" stepNumber={2}>
    ```shellscript theme={null}
    npm install && npm install @auth0/auth0-spa-js
    ```
  </Step>

  <Step title="Configura tu aplicación de Auth0" stepNumber={3}>
    A continuación, debes crear una nueva aplicación en tu inquilino de Auth0 y añadir las variables de entorno a tu proyecto.

    Tienes tres opciones para configurar tu aplicación de Auth0: usar la herramienta Quick Setup (recomendado), ejecutar un comando de la CLI o configurarla manualmente desde el Dashboard:

    <Tabs>
      <Tab title="Quick Setup (recomendado)">
        Crea una aplicación de Auth0 y copia el archivo `.env` preconfigurado con los valores correctos.

        <CreateInteractiveApp placeholderText="Svelte" appType="spa" allowedCallbackUrls={["http://localhost:5173"]} allowedLogoutUrls={["http://localhost:5173"]} allowedOriginUrls={["http://localhost:5173"]} />

        <AuthCodeBlock children={localEnvSnippet} language="shellscript" filename=".env" />
      </Tab>

      <Tab title="CLI">
        Ejecuta el siguiente comando en el directorio raíz de tu proyecto para crear una aplicación de Auth0 y generar un archivo `.env`:

        <CodeGroup>
          ```shellscript Mac theme={null}
          # Instala Auth0 CLI (si aún no está instalado)
          brew tap auth0/auth0-cli && brew install auth0

          # Configura la aplicación de Auth0 y genera el archivo .env
          auth0 qs setup --app --type spa --framework svelte --build-tool vite --name "My App" --port 5173
          ```

          ```powershell Windows theme={null}
          # Instala Auth0 CLI (si aún no está instalado)
          scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
          scoop install auth0

          # Configura la aplicación de Auth0 y genera el archivo .env
          auth0 qs setup --app --type spa --framework svelte --build-tool vite --name "My App" --port 5173
          ```
        </CodeGroup>

        <Note>
          Este comando hará lo siguiente:

          1. Comprobará si has iniciado sesión (y te pedirá que lo hagas si es necesario)
          2. Creará una Single Page Application de Auth0 configurada para `http://localhost:5173`
          3. Generará un archivo `.env` con `VITE_AUTH0_DOMAIN` y `VITE_AUTH0_CLIENT_ID`
        </Note>
      </Tab>

      <Tab title="Dashboard">
        Antes de empezar, crea un archivo `.env` en el directorio raíz de tu proyecto

        ```shellscript .env theme={null}
        VITE_AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
        VITE_AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
        ```

        1. Ve al [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Haz clic en **Applications** > **Applications** > **Create Application**
        3. En la ventana emergente, introduce un nombre para tu aplicación, selecciona `Single Page Web Application` como tipo de aplicación y haz clic en **Create**
        4. Ve a la pestaña **Settings** en la página Application Details
        5. Sustituye `YOUR_AUTH0_APP_DOMAIN` y `YOUR_AUTH0_APP_CLIENT_ID` en el archivo `.env` por los valores de **Domain** y **Client ID** del dashboard

        Por último, en la pestaña **Settings** de la página Application Details, configura las siguientes URL:

        **Allowed Callback URLs:**

        ```
        http://localhost:5173
        ```

        **Allowed Logout URLs:**

        ```
        http://localhost:5173
        ```

        **Allowed Web Origins:**

        ```
        http://localhost:5173
        ```

        <Info>
          **Allowed Callback URLs** son una medida de seguridad fundamental para garantizar que los usuarios vuelvan de forma segura a tu aplicación después de autenticarse. Sin una URL coincidente, el proceso de inicio de sesión fallará y los usuarios verán una página de error de Auth0 en lugar de acceder a tu aplicación.

          **Allowed Logout URLs** son esenciales para ofrecer una experiencia fluida al cerrar sesión. Sin una URL coincidente, los usuarios no serán redirigidos de vuelta a tu aplicación después del logout y, en su lugar, se quedarán en una página genérica de Auth0.

          **Allowed Web Origins** es fundamental para la autenticación silenciosa. Sin esta configuración, los usuarios cerrarán sesión al actualizar la página o al volver más tarde a tu aplicación.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Crear el store de Auth0" stepNumber={4}>
    Cree el archivo del store

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      mkdir -p src/lib/stores && touch src/lib/stores/auth.ts
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/lib/stores
      New-Item -ItemType File -Path src/lib/stores/auth.ts
      ```
    </CodeGroup>

    Agregue el siguiente código para administrar el estado de autenticación

    ```typescript src/lib/stores/auth.ts lines expandable theme={null}
      import { writable, derived, get, type Readable } from 'svelte/store';
      import { createAuth0Client, type Auth0Client, type User } from '@auth0/auth0-spa-js';
      import { browser } from '$app/environment';

      export const auth0Client = writable<Auth0Client | null>(null);
      export const user = writable<User | null>(null);
      export const isAuthenticated = writable<boolean>(false);
      export const isLoading = writable<boolean>(true);
      export const error = writable<string | null>(null);

      // Stores derivados
      export const isLoggedIn: Readable<boolean> = derived(
        [isAuthenticated, isLoading],
        ([$isAuthenticated, $isLoading]) => $isAuthenticated && !$isLoading
      );

      export async function initializeAuth() {
        if (!browser) return;
        
        try {
          const client = await createAuth0Client({
            domain: import.meta.env.VITE_AUTH0_DOMAIN,
            clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
            authorizationParams: {
              redirect_uri: window.location.origin
            },
            useRefreshTokens: true,
            cacheLocation: 'localstorage'
          });

          auth0Client.set(client);

          // Gestionar callback
          if (window.location.search.includes('code=')) {
            await client.handleRedirectCallback();
            window.history.replaceState({}, document.title, window.location.pathname);
          }

          // Verificar estado de autenticación
          const authenticated = await client.isAuthenticated();
          isAuthenticated.set(authenticated);

          if (authenticated) {
            const userData = await client.getUser();
            user.set(userData || null);
          }

          error.set(null);
        } catch (err) {
          console.error('Error de inicialización de autenticación:', err);
          error.set(err instanceof Error ? err.message : 'Authentication initialization failed');
        } finally {
          isLoading.set(false);
        }
      }

      export async function login() {
        const client = get(auth0Client);
        if (client) {
          await client.loginWithRedirect();
        }
      }

      export async function logout() {
        const client = get(auth0Client);
        if (client) {
          client.logout({ 
            logoutParams: { 
              returnTo: window.location.origin 
            } 
          });
        }
      }

      export async function getToken(): Promise<string | null> {
        const client = get(auth0Client);
        if (!client) return null;
        
        try {
          return await client.getTokenSilently();
        } catch (err: any) {
          if (err.error === 'login_required') {
            await login();
          }
          return null;
        }
      }
    ```
  </Step>

  <Step title="Crear los componentes Login, Logout y Profile" stepNumber={5}>
    Crear archivos de componentes

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      mkdir -p src/lib/components && touch src/lib/components/LoginButton.svelte && touch src/lib/components/LogoutButton.svelte && touch src/lib/components/Profile.svelte
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/lib/components
      New-Item -ItemType File -Path src/lib/components/LoginButton.svelte
      New-Item -ItemType File -Path src/lib/components/LogoutButton.svelte
      New-Item -ItemType File -Path src/lib/components/Profile.svelte
      ```
    </CodeGroup>

    Y agrega los siguientes fragmentos de código

    <AuthCodeGroup>
      ```svelte src/lib/components/LoginButton.svelte lines expandable theme={null}
      <script lang="ts">
        import { login } from '$lib/stores/auth';

        async function handleLogin() {
          await login();
        }
      </script>

      <button 
        on:click={handleLogin}
        class="button login"
      >
        Log In
      </button>

      <style>
        .button {
          padding: 1.1rem 2.8rem;
          font-size: 1.2rem;
          font-weight: 600;
          border-radius: 10px;
          border: none;
          cursor: pointer;
          transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
          box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
          text-transform: uppercase;
          letter-spacing: 0.08em;
          outline: none;
        }

        .button:focus {
          box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
        }

        .button.login {
          background-color: #63b3ed;
          color: #1a1e27;
        }

        .button.login:hover {
          background-color: #4299e1;
          transform: translateY(-5px) scale(1.03);
          box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
        }
      </style>
      ```

      ```svelte src/lib/components/LogoutButton.svelte lines expandable theme={null}
      <script lang="ts">
        import { logout } from '$lib/stores/auth';

        async function handleLogout() {
          await logout();
        }
      </script>

      <button
        on:click={handleLogout}
        class="button logout"
      >
        Log Out
      </button>

      <style>
        .button {
          padding: 1.1rem 2.8rem;
          font-size: 1.2rem;
          font-weight: 600;
          border-radius: 10px;
          border: none;
          cursor: pointer;
          transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
          box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
          text-transform: uppercase;
          letter-spacing: 0.08em;
          outline: none;
        }

        .button:focus {
          box-shadow: 0 0 0 4px rgba(252, 129, 129, 0.5);
        }

        .button.logout {
          background-color: #fc8181;
          color: #1a1e27;
        }

        .button.logout:hover {
          background-color: #e53e3e;
          transform: translateY(-5px) scale(1.03);
          box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
        }
      </style>
      ```

      ```svelte src/lib/components/Profile.svelte lines expandable theme={null}
      <script lang="ts">
        import { user, isAuthenticated, isLoading } from '$lib/stores/auth';
        
        const placeholderImage = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='50' fill='%2363b3ed'/%3E%3Cpath d='M50 45c7.5 0 13.64-6.14 13.64-13.64S57.5 17.72 50 17.72s-13.64 6.14-13.64 13.64S42.5 45 50 45zm0 6.82c-9.09 0-27.28 4.56-27.28 13.64v3.41c0 1.88 1.53 3.41 3.41 3.41h47.74c1.88 0 3.41-1.53 3.41-3.41v-3.41c0-9.08-18.19-13.64-27.28-13.64z' fill='%23fff'/%3E%3C/svg%3E`;
        
        function handleImageError(event: Event) {
          const target = event.target as HTMLImageElement;
          target.src = placeholderImage;
        }
      </script>

      {#if $isLoading}
        <div class="loading-text">Loading profile...</div>
      {:else if $isAuthenticated && $user}
        <div class="profile-container">
          <img 
            src={$user.picture || placeholderImage} 
            alt={$user.name || 'User'} 
            class="profile-picture"
            on:error={handleImageError}
          />
          <div class="profile-info">
            <div class="profile-name">
              {$user.name || 'Unknown User'}
            </div>
            <div class="profile-email">
              {$user.email || ''}
            </div>
          </div>
        </div>
      {/if}

      <style>
        .loading-text {
          font-size: 1.8rem;
          font-weight: 500;
          color: #a0aec0;
          animation: pulse 1.5s infinite ease-in-out;
        }

        .profile-container {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 1rem;
        }

        .profile-picture {
          width: 110px;
          height: 110px;
          border-radius: 50%;
          object-fit: cover;
          border: 3px solid #63b3ed;
          transition: transform 0.3s ease-in-out;
        }

        .profile-picture:hover {
          transform: scale(1.05);
        }

        .profile-info {
          text-align: center;
        }

        .profile-name {
          font-size: 2rem;
          font-weight: 600;
          color: #f7fafc;
          margin-bottom: 0.5rem;
        }

        .profile-email {
          font-size: 1.15rem;
          color: #a0aec0;
        }

        @keyframes pulse {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.6; }
        }
      </style>
      ```

      ```svelte src/routes/+layout.svelte expandable lines theme={null}
      <script lang="ts">
        import { onMount } from 'svelte';
        import { initializeAuth } from '$lib/stores/auth';

        onMount(() => {
          initializeAuth();
        });
      </script>

      <main>
        <slot />
      </main>

      <style>
        :global(body) {
          margin: 0;
          font-family: 'Inter', sans-serif;
          background-color: #1a1e27;
          min-height: 100vh;
          color: #e2e8f0;
        }

        main {
          min-height: 100vh;
          display: flex;
          justify-content: center;
          align-items: center;
          padding: 1rem;
          box-sizing: border-box;
        }
      </style>
      ```

      ```svelte src/routes/+page.svelte expandable lines theme={null}
      <script lang="ts">
        import { isAuthenticated, isLoading, error, user } from '$lib/stores/auth';
        import LoginButton from '$lib/components/LoginButton.svelte';
        import LogoutButton from '$lib/components/LogoutButton.svelte';
        import Profile from '$lib/components/Profile.svelte';
      </script>

      <svelte:head>
        <title>Auth0 Svelte Sample</title>
        <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
      </svelte:head>

      <div class="app-container">
        {#if $isLoading}
          <div class="loading-state">
            <div class="loading-text">Loading...</div>
          </div>
        {:else if $error}
          <div class="error-state">
            <div class="error-title">Oops!</div>
            <div class="error-message">Something went wrong</div>
            <div class="error-sub-message">{$error}</div>
          </div>
        {:else}
          <div class="main-card-wrapper">
            <img 
              src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
              alt="Auth0 Logo" 
              class="auth0-logo"
            />
            <h1 class="main-title">Welcome to Sample0</h1>

            {#if $isAuthenticated}
              <div class="logged-in-section">
                <div class="logged-in-message">✅ Successfully authenticated!</div>
                <h2 class="profile-section-title">Your Profile</h2>
                <div class="profile-card">
                  <Profile />
                </div>
                <LogoutButton />
              </div>
            {:else}
              <div class="action-card">
                <p class="action-text">Get started by signing in to your account</p>
                <LoginButton />
              </div>
            {/if}
          </div>
        {/if}
      </div>

      <style>
        .app-container {
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          min-height: 100vh;
          width: 100%;
          padding: 1rem;
          box-sizing: border-box;
        }

        .loading-state, .error-state {
          background-color: #2d313c;
          border-radius: 15px;
          box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
          padding: 3rem;
          text-align: center;
        }

        .loading-text {
          font-size: 1.8rem;
          font-weight: 500;
          color: #a0aec0;
          animation: pulse 1.5s infinite ease-in-out;
        }

        .error-state {
          background-color: #c53030;
          color: #fff;
        }

        .error-title {
          font-size: 2.8rem;
          font-weight: 700;
          margin-bottom: 0.5rem;
        }

        .error-message {
          font-size: 1.3rem;
          margin-bottom: 0.5rem;
        }

        .error-sub-message {
          font-size: 1rem;
          opacity: 0.8;
        }

        .main-card-wrapper {
          background-color: #262a33;
          border-radius: 20px;
          box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 2rem;
          padding: 3rem;
          max-width: 500px;
          width: 90%;
          animation: fadeInScale 0.8s ease-out forwards;
        }

        .auth0-logo {
          width: 160px;
          margin-bottom: 1.5rem;
          opacity: 0;
          animation: slideInDown 1s ease-out forwards 0.2s;
        }

        .main-title {
          font-size: 2.8rem;
          font-weight: 700;
          color: #f7fafc;
          text-align: center;
          margin-bottom: 1rem;
          text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
          opacity: 0;
          animation: fadeIn 1s ease-out forwards 0.4s;
        }

        .action-card {
          background-color: #2d313c;
          border-radius: 15px;
          box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
          padding: 2.5rem;
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 1.8rem;
          width: calc(100% - 2rem);
          opacity: 0;
          animation: fadeIn 1s ease-out forwards 0.6s;
        }

        .action-text {
          font-size: 1.25rem;
          color: #cbd5e0;
          text-align: center;
          line-height: 1.6;
          font-weight: 400;
        }

        .logged-in-section {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 1.5rem;
          width: 100%;
        }

        .logged-in-message {
          font-size: 1.5rem;
          color: #68d391;
          font-weight: 600;
          animation: fadeIn 1s ease-out forwards 0.8s;
        }

        .profile-section-title {
          font-size: 2.2rem;
          animation: slideInUp 1s ease-out forwards 1s;
        }

        .profile-card {
          padding: 2.2rem;
          animation: scaleIn 0.8s ease-out forwards 1.2s;
        }

        @keyframes fadeIn {
          from { opacity: 0; }
          to { opacity: 1; }
        }

        @keyframes fadeInScale {
          from { opacity: 0; transform: scale(0.95); }
          to { opacity: 1; transform: scale(1); }
        }

        @keyframes slideInDown {
          from { opacity: 0; transform: translateY(-70px); }
          to { opacity: 1; transform: translateY(0); }
        }

        @keyframes slideInUp {
          from { opacity: 0; transform: translateY(50px); }
          to { opacity: 1; transform: translateY(0); }
        }

        @keyframes pulse {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.6; }
        }

        @keyframes scaleIn {
          from { opacity: 0; transform: scale(0.8); }
          to { opacity: 1; transform: scale(1); }
        }

        @media (max-width: 600px) {
          .main-card-wrapper {
            padding: 2rem;
            margin: 1rem;
          }

          .main-title {
            font-size: 2.2rem;
          }

          .auth0-logo {
            width: 120px;
          }
        }
      </style>
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Ejecute la aplicación" stepNumber={6}>
    ```shellscript theme={null}
    npm run dev
    ```
  </Step>
</Steps>

<Check>
  **Punto de control**

  Ahora deberías tener una página de Login de Auth0 completamente funcional ejecutándose en [localhost](http://localhost:5173/)
</Check>

***

<div id="troubleshooting">
  ## Solución de problemas
</div>

<Accordion title="Login no funciona">
  Si al hacer clic en el botón de Login no pasa nada:

  1. Abre las DevTools del navegador (F12) y revisa la pestaña Console
  2. Verifica que el archivo `.env` tenga credenciales reales de Auth0
  3. Comprueba que la aplicación de Auth0 tenga configuradas las URL de callback correctas
  4. Asegúrate de que `VITE_AUTH0_DOMAIN` sea solo el dominio (por ejemplo, `tenant.auth0.com`) sin `https://`
</Accordion>

<Accordion title="Errores de autenticación">
  **"Callback URL mismatch"**:

  * Ve a Auth0 Dashboard → Applications → Your App → Settings
  * Agrega `http://localhost:5173` a Allowed Callback URLs, Allowed Logout URLs y Allowed Web Origins
  * Haz clic en "Save Changes"

  **"Invalid state"**:

  * Borra la caché y las cookies del navegador
  * Inténtalo en una ventana de incógnito o privada
</Accordion>

<Accordion title="Problemas del servidor de desarrollo">
  Si `npm run dev` falla:

  * Ejecuta `npm run check` para ver los errores de TypeScript
  * Verifica que todos los archivos se hayan creado correctamente
  * Comprueba que todas las dependencias estén instaladas: `npm install`
</Accordion>

<Tip>
  ¿Sigues sin resolverlo? Consulta la [Auth0 Community](https://community.auth0.com/) o [SvelteKit Discord](https://svelte.dev/chat) para obtener ayuda.
</Tip>
