> ## 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.

> En esta guía se muestra cómo integrar Auth0, agregar autenticación y mostrar información del perfil de usuario en una aplicación web de Express.js mediante el SDK express-openid-connect.

# Agrega el Login a tu aplicación de Express

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 />;
};

<HowToSchema />

<Accordion title="Usa IA para integrar Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  Si usas un asistente de programación con IA como Claude Code, Cursor o GitHub Copilot, puedes añadir la autenticación de Auth0 automáticamente en minutos con [agent skills](https://agentskills.io/home).

  **Instalar:**

  ```bash theme={null}
  npx skills add https://github.com/auth0/agent-skills --skill auth0-express
  ```

  **Luego, pídele a tu asistente de IA:**

  ```text theme={null}
  Add Auth0 authentication to my Express app
  ```

  Tu asistente de IA creará automáticamente tu aplicación de Auth0, obtendrá las credenciales, instalará `express-openid-connect`, configurará el middleware y preparará tus rutas. [Documentación completa de agent skills →](/es/docs/quickstart/agent-skills)
</Accordion>

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

  * [Node.js](https://nodejs.org/) 18 LTS o una versión posterior
  * [npm](https://www.npmjs.com/) 10+ o [yarn](https://yarnpkg.com/) 1.22+
  * [jq](https://jqlang.github.io/jq/) - Requerido para configurar la CLI de Auth0 (opcional)

  **Compatibilidad de versiones de Express:** Este inicio rápido funciona con Express 4.17.0 y versiones posteriores.
</Note>

<div id="get-started">
  ## Primeros pasos
</div>

En esta guía se muestra cómo integrar Auth0, añadir autenticación y mostrar la información del perfil de usuario en una aplicación web de Express.js mediante el SDK `express-openid-connect`.

***

<div id="1-create-a-new-project">
  ## 1. Cree un proyecto nuevo
</div>

Cree un nuevo directorio para su aplicación Express e inicialice un proyecto de Node.js.

```bash theme={null}
mkdir auth0-express && cd auth0-express
```

```bash theme={null}
npm init -y
```

Crea la estructura del proyecto:

```bash theme={null}
touch index.js .env
```

***

<div id="2-install-the-auth0-express-sdk">
  ## 2. Instala el SDK de Auth0 para Express
</div>

Instala `express-openid-connect` junto con Express y dotenv para gestionar las variables de entorno.

```bash theme={null}
npm install express express-openid-connect dotenv
```

Para el desarrollo, instala nodemon para que tu servidor se reinicie automáticamente cuando haya cambios en los archivos:

```bash theme={null}
npm install --save-dev nodemon
```

Actualiza tu `package.json` para añadir scripts de inicio:

📁 **package.json**

```json theme={null}
{
  "name": "auth0-express",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js"
  },
  "dependencies": {
    "dotenv": "^16.3.1",
    "express": "^4.18.2",
    "express-openid-connect": "^2.17.1"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  }
}
```

***

<div id="3-setup-your-auth0-app">
  ## 3. Configura tu aplicación de Auth0
</div>

A continuación, debes crear una aplicación nueva en tu inquilino de Auth0 y agregar las variables de entorno a tu proyecto.

Puedes hacerlo automáticamente ejecutando un comando de la CLI o manualmente desde el Dashboard:

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

    **macOS / Linux:**

    ```bash theme={null}
    AUTH0_APP_NAME="My Express App" && \
    auth0 apps create -n "${AUTH0_APP_NAME}" -t regular \
      --callbacks http://localhost:3000 \
      --logout-urls http://localhost:3000 \
      --json | jq -r '"ISSUER_BASE_URL=https://\(.domain)\nCLIENT_ID=\(.client_id)\nSECRET='$(openssl rand -hex 32)'\nBASE_URL=http://localhost:3000"' > .env
    ```

    **Windows (PowerShell):**

    ```powershell theme={null}
    $appName = "My Express App"
    auth0 apps create -n $appName -t regular `
      --callbacks http://localhost:3000 `
      --logout-urls http://localhost:3000 `
      --json | ConvertFrom-Json | ForEach-Object {
        "ISSUER_BASE_URL=https://$($_.domain)`nCLIENT_ID=$($_.client_id)`nSECRET=$([guid]::NewGuid().ToString())`nBASE_URL=http://localhost:3000"
      } | Out-File .env -Encoding utf8
    ```

    <Note>
      Si aún no instalaste CLI de Auth0, ejecuta:

      ```bash theme={null}
      brew tap auth0/auth0-cli && brew install auth0
      ```

      Luego, autentícate con `auth0 login`.
    </Note>
  </Tab>

  <Tab title="Dashboard">
    1. Ve al [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
    2. Ve a **Applications** → **Create Application**
    3. Ingresa un nombre para tu aplicación (por ejemplo, "My Express App")
    4. Selecciona **Regular Web Applications** y haz clic en **Create**
    5. En la pestaña **Settings**, configura lo siguiente:

    | Configuración         | Valor                   |
    | --------------------- | ----------------------- |
    | Allowed Callback URLs | `http://localhost:3000` |
    | Allowed Logout URLs   | `http://localhost:3000` |

    6. Desplázate hacia abajo y haz clic en **Save Changes**
    7. Copia los valores de **Domain** y **Client ID** de la sección **Basic Information**

    Crea tu archivo `.env` con los siguientes valores:

    📁 **.env**

    ```bash theme={null}
    ISSUER_BASE_URL=https://YOUR_AUTH0_DOMAIN
    CLIENT_ID=YOUR_CLIENT_ID
    SECRET=use-a-long-random-string-at-least-32-characters
    BASE_URL=http://localhost:3000
    ```

    <Warning>
      Reemplaza `YOUR_AUTH0_DOMAIN` por el dominio de tu inquilino de Auth0 (por ejemplo, `dev-abc123.us.auth0.com`) y `YOUR_CLIENT_ID` por el ID de cliente de tu aplicación en el dashboard.
    </Warning>

    Genera un secreto seguro para cifrar sesiones:

    ```bash theme={null}
    openssl rand -hex 32
    ```

    Copia el resultado y úsalo como valor de `SECRET` en tu archivo `.env`.
  </Tab>
</Tabs>

***

<div id="4-configure-the-middleware">
  ## 4. Configura el middleware
</div>

Agrega el middleware de Auth0 a tu aplicación de Express. El middleware `auth()` se encarga de gestionar las sesiones y crea automáticamente las rutas `/login`, `/logout` y `/callback`.

📁 **index.js**

```javascript theme={null}
require('dotenv').config();
const express = require('express');
const { auth } = require('express-openid-connect');

const app = express();
const port = process.env.PORT || 3000;

// Configuración de Auth0
const config = {
  authRequired: false,      // Permitir rutas públicas
  auth0Logout: true,        // Usar el endpoint de logout de Auth0
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
};

// Aplicar el middleware de autenticación
app.use(auth(config));

// Ruta de inicio - pública
app.get('/', (req, res) => {
  res.send(req.oidc.isAuthenticated() ? 'Logged in' : 'Logged out');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
```

**Qué hace esto:**

* `authRequired: false` permite que tanto los usuarios autenticados como los no autenticados accedan a las rutas de forma predeterminada
* `auth0Logout: true` garantiza que los usuarios cierren sesión tanto en Auth0 como en tu aplicación
* El middleware proporciona automáticamente las rutas `/login`, `/logout` y `/callback`
* La sesión del usuario se almacena en una cookie cifrada

***

<div id="5-create-login-logout-and-profile-routes">
  ## 5. Cree rutas de inicio de sesión, cierre de sesión y perfil
</div>

Ahora agregue rutas para mostrar enlaces para iniciar y cerrar sesión, y una página de perfil protegida.

📁 **index.js**

```javascript theme={null}
require('dotenv').config();
const express = require('express');
const { auth, requiresAuth } = require('express-openid-connect');

const app = express();
const port = process.env.PORT || 3000;

// Configuración de Auth0
const config = {
  authRequired: false,
  auth0Logout: true,
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
};

// Aplicar el middleware de autenticación
app.use(auth(config));

// Ruta de inicio - muestra el estado de login/logout
app.get('/', (req, res) => {
  const isAuthenticated = req.oidc.isAuthenticated();

  res.send(`
    <html>
      <head>
        <title>Auth0 Express Quickstart</title>
        <style>
          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 2rem; max-width: 600px; margin: 0 auto; }
          a { color: #0066cc; text-decoration: none; margin-right: 1rem; }
          a:hover { text-decoration: underline; }
          .status { padding: 1rem; border-radius: 4px; margin: 1rem 0; }
          .logged-in { background: #d4edda; color: #155724; }
          .logged-out { background: #f8d7da; color: #721c24; }
        </style>
      </head>
      <body>
        <h1>Auth0 Express Quickstart</h1>
        <div class="status ${isAuthenticated ? 'logged-in' : 'logged-out'}">
          ${isAuthenticated ? '✓ You are logged in' : '✗ You are logged out'}
        </div>
        <nav>
          ${isAuthenticated
            ? '<a href="/profile">Profile</a> | <a href="/logout">Logout</a>'
            : '<a href="/login">Login</a>'}
        </nav>
      </body>
    </html>
  `);
});

// Ruta de perfil protegida - requiere autenticación
app.get('/profile', requiresAuth(), (req, res) => {
  const user = req.oidc.user;

  res.send(`
    <html>
      <head>
        <title>Profile - Auth0 Express</title>
        <style>
          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 2rem; max-width: 600px; margin: 0 auto; }
          a { color: #0066cc; text-decoration: none; }
          img { border-radius: 50%; }
          pre { background: #f4f4f4; padding: 1rem; border-radius: 4px; overflow-x: auto; }
          .card { border: 1px solid #ddd; border-radius: 8px; padding: 1.5rem; margin: 1rem 0; }
        </style>
      </head>
      <body>
        <h1>User Profile</h1>
        <div class="card">
          ${user.picture ? `<img src="${user.picture}" alt="Profile" width="80" />` : ''}
          <h2>${user.name || user.nickname || 'User'}</h2>
          <p><strong>Email:</strong> ${user.email || 'N/A'}</p>
        </div>
        <h3>Full User Object</h3>
        <pre>${JSON.stringify(user, null, 2)}</pre>
        <nav>
          <a href="/">← Back to Home</a> | <a href="/logout">Logout</a>
        </nav>
      </body>
    </html>
  `);
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
```

**Puntos clave:**

* El middleware `requiresAuth()` protege la ruta `/profile`: los usuarios no autenticados se redirigen al inicio de sesión
* `req.oidc.user` contiene la información del perfil del usuario autenticado
* `req.oidc.isAuthenticated()` devuelve un valor booleano que indica si el usuario ha iniciado sesión
* El middleware `auth()` crea automáticamente las rutas de inicio y cierre de sesión (`/login`, `/logout`)

***

<div id="6-run-your-app">
  ## 6. Ejecuta la aplicación
</div>

Inicia el servidor de desarrollo:

```bash theme={null}
npm run dev
```

Abre [http://localhost:3000](http://localhost:3000) en tu navegador.

<Check>
  **Verificación**

  Ahora deberías tener una página de Login de Auth0 totalmente funcional. Cuando:

  1. Haces clic en "Login" - se te redirige a la página de Universal Login de Auth0
  2. Completas la autenticación - se te redirige de nuevo a tu aplicación
  3. Visitas "/profile" - ves tu información de usuario
  4. Haces clic en "Logout" - cierras sesión tanto en tu aplicación como en Auth0
</Check>

***

<div id="advanced-usage">
  ## Uso avanzado
</div>

<AccordionGroup>
  <Accordion title="Proteger rutas específicas con requiresAuth()">
    Utilice el middleware `requiresAuth()` para proteger las rutas individuales que requieren autenticación:

    ```javascript theme={null}
    const { auth, requiresAuth } = require('express-openid-connect');

    app.use(auth({ authRequired: false }));

    // Ruta pública
    app.get('/', (req, res) => {
      res.send('Welcome! This is public.');
    });

    // Rutas protegidas
    app.get('/dashboard', requiresAuth(), (req, res) => {
      res.send(`Hello ${req.oidc.user.name}, welcome to your dashboard!`);
    });

    app.get('/settings', requiresAuth(), (req, res) => {
      res.send('Settings page - only for authenticated users');
    });
    ```

    También puede proteger todas las rutas dentro de una ruta específica con el Router de Express:

    ```javascript theme={null}
    const protectedRouter = express.Router();

    // Todas las rutas en este router requieren autenticación
    protectedRouter.use(requiresAuth());

    protectedRouter.get('/dashboard', (req, res) => {
      res.send('Protected dashboard');
    });

    protectedRouter.get('/settings', (req, res) => {
      res.send('Protected settings');
    });

    app.use('/app', protectedRouter);
    // Rutas: /app/dashboard, /app/settings están todas protegidas
    ```
  </Accordion>

  <Accordion title="Llamar a APIs protegidas con tokens de acceso">
    Para llamar a APIs externas que requieren un token de acceso, configure el SDK para solicitar uno:

    📁 **index.js** (configuración actualizada)

    ```javascript theme={null}
    const config = {
      authRequired: false,
      auth0Logout: true,
      secret: process.env.SECRET,
      baseURL: process.env.BASE_URL,
      clientID: process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
      clientSecret: process.env.CLIENT_SECRET,  // Requerido para el flujo de código
      authorizationParams: {
        response_type: 'code',
        audience: process.env.API_AUDIENCE,     // El identificador de tu API
        scope: 'openid profile email read:data',
      },
    };
    ```

    Agrega esto a tu archivo `.env`:

    ```bash theme={null}
    CLIENT_SECRET=your_client_secret_from_dashboard
    API_AUDIENCE=https://your-api.example.com
    ```

    Luego, usa el token de acceso para llamar a la API:

    ```javascript theme={null}
    app.get('/api-data', requiresAuth(), async (req, res) => {
      try {
        let { token_type, access_token, isExpired, refresh } = req.oidc.accessToken;

        // Actualizar el token si expiró
        if (isExpired()) {
          const refreshed = await refresh();
          access_token = refreshed.access_token;
        }

        // Llamar a tu API protegida
        const response = await fetch('https://your-api.example.com/data', {
          headers: {
            Authorization: `${token_type} ${access_token}`,
          },
        });

        const data = await response.json();
        res.json(data);
      } catch (error) {
        console.error('API call failed:', error);
        res.status(500).json({ error: 'Failed to fetch data' });
      }
    });
    ```

    <Note>
      Para obtener tokens de actualización, añade `offline_access` a tu scope:

      ```javascript theme={null}
      scope: 'openid profile email offline_access read:data',
      ```
    </Note>
  </Accordion>

  <Accordion title="Uso de la autorización basada en claims">
    Proteja las rutas según los claim del usuario (roles, permisos, etc.):

    ```javascript theme={null}
    const { auth, requiresAuth, claimEquals, claimIncludes, claimCheck } = require('express-openid-connect');

    app.use(auth({ authRequired: false }));

    // Solo usuarios con role = 'admin'
    app.get('/admin', claimEquals('role', 'admin'), (req, res) => {
      res.send('Admin dashboard');
    });

    // Usuarios cuyo array roles incluye 'editor'
    app.get('/editor', claimIncludes('roles', 'editor'), (req, res) => {
      res.send('Editor dashboard');
    });

    // Verificación de claim personalizada con lógica
    app.get('/premium', claimCheck((req, claims) => {
      return claims.subscription === 'premium' || claims.role === 'admin';
    }), (req, res) => {
      res.send('Premium content');
    });
    ```

    <Note>
      Los claims como `role` deben agregarse a los tokens mediante Rules o Actions de Auth0. [Obtén más información sobre cómo agregar claims personalizados](https://auth0.com/docs/customize/actions/flows-and-triggers/login-flow/add-user-roles-to-id-and-access-tokens).
    </Note>
  </Accordion>

  <Accordion title="Almacén de sesiones personalizado (Redis)">
    Para entornos de producción o si ejecuta varias instancias del servidor, use un almacén de sesiones personalizado:

    ```bash theme={null}
    npm install redis connect-redis
    ```

    ```javascript theme={null}
    const { auth } = require('express-openid-connect');
    const { createClient } = require('redis');
    const RedisStore = require('connect-redis').default;

    // Crear cliente de Redis
    const redisClient = createClient({
      url: process.env.REDIS_URL || 'redis://localhost:6379',
    });
    redisClient.connect().catch(console.error);

    const config = {
      authRequired: false,
      auth0Logout: true,
      secret: process.env.SECRET,
      baseURL: process.env.BASE_URL,
      clientID: process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
      session: {
        store: new RedisStore({ client: redisClient }),
      },
    };

    app.use(auth(config));
    ```

    **Cuándo usar un almacén de sesiones personalizado:**

    * Ejecuta varias instancias del servidor (balanceo de carga)
    * Los datos de la sesión superan el límite de tamaño de las cookies (\~4 KB)
    * Necesita persistencia de la sesión entre reinicios del servidor
    * Usa Back-Channel Logout
  </Accordion>

  <Accordion title="Gestión de errores">
    Agrega un manejo adecuado de los errores de autenticación:

    ```javascript theme={null}
    const { auth } = require('express-openid-connect');

    app.use(auth({
      authRequired: false,
      auth0Logout: true,
      secret: process.env.SECRET,
      baseURL: process.env.BASE_URL,
      clientID: process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
      errorOnRequiredAuth: true,  // Devuelve 401 en lugar de redirigir para rutas de API
    }));

    // Manejador de errores personalizado
    app.use((err, req, res, next) => {
      // Gestionar errores de autenticación
      if (err.statusCode === 401) {
        // Para solicitudes de API, devolver JSON
        if (req.accepts('json')) {
          return res.status(401).json({
            error: 'Authentication required',
            login_url: '/login',
          });
        }
        // Para solicitudes del navegador, redirigir al login
        return res.redirect('/login');
      }

      // Registrar el error (no exponer detalles al cliente)
      console.error('Application error:', err.message);

      res.status(err.statusCode || 500).json({
        error: 'An unexpected error occurred',
      });
    });
    ```
  </Accordion>
</AccordionGroup>

***

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

<AccordionGroup>
  <Accordion title="Problemas comunes y soluciones">
    ### Error "Invalid state" tras iniciar sesión

    **Problema:** El valor de `state` no coincide entre la solicitud de autenticación y el callback.

    **Soluciones:**

    1. Asegúrate de usar HTTPS en producción
    2. Comprueba que las cookies se estén estableciendo correctamente (que el navegador no las bloquee)
    3. Verifica que la URL de callback coincida exactamente con la configurada en Auth0 Dashboard

    ### "req.oidc is undefined"

    **Problema:** El middleware `auth()` no se aplica antes de acceder a `req.oidc`.

    **Solución:** Asegúrate de que se llame a `app.use(auth(config))` antes de cualquier ruta que acceda a `req.oidc`:

    ```javascript theme={null}
    // ✅ Orden correcto
    app.use(auth(config));
    app.get('/profile', requiresAuth(), (req, res) => { ... });

    // ❌ Orden incorrecto
    app.get('/profile', requiresAuth(), (req, res) => { ... });
    app.use(auth(config));
    ```

    ### Sesión demasiado grande / errores de cookies

    **Problema:** Los datos de la sesión del usuario superan los límites de tamaño de las cookies.

    **Solución:** Usa un almacén de sesiones personalizado, como Redis:

    ```javascript theme={null}
    session: {
      store: new RedisStore({ client: redisClient }),
    }
    ```

    ### La URL de callback no coincide

    **Problema:** Error "Callback URL mismatch" de Auth0.

    **Solución:**

    1. Ve a tu Auth0 Dashboard → Applications → Your App → Settings
    2. Añade `http://localhost:3000` (o tu URL de producción) a **Allowed Callback URLs**
    3. La URL debe coincidir **exactamente** (incluidas las barras finales)

    ### Las variables de entorno no se cargan

    **Problema:** Los valores de configuración son `undefined`.

    **Solución:**

    1. Asegúrate de que `require('dotenv').config()` esté al principio de tu archivo de entrada
    2. Verifica que el archivo `.env` esté en el directorio raíz
    3. Comprueba si hay errores tipográficos en los nombres de las variables

    ```javascript theme={null}
    // Depuración: muestra los valores de configuración (¡elimínalo en producción!)
    console.log('Config check:', {
      hasSecret: !!process.env.SECRET,
      hasClientID: !!process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
    });
    ```
  </Accordion>
</AccordionGroup>

***

<div id="next-steps">
  ## Siguientes pasos
</div>

Ahora que ya tienes la autenticación en funcionamiento, considera explorar lo siguiente:

* **[Agregar autorización](https://auth0.com/docs/manage-users/access-control/rbac)** - Implementa el control de acceso basado en roles
* **[Llamar a API protegidas](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens)** - Usa tokens de acceso para llamar a tus API de backend
* **[Personalizar Universal Login](https://auth0.com/docs/customize/universal-login-pages)** - Personaliza la experiencia de inicio de sesión con tu marca
* **[Agregar conexiones sociales](https://auth0.com/docs/connections/social)** - Habilita Google, GitHub y otros inicios de sesión con cuentas sociales
* **[Implementar MFA](https://auth0.com/docs/secure/multi-factor-authentication)** - Agrega autenticación multifactor

***

<div id="resources">
  ## Recursos
</div>

* **[express-openid-connect GitHub](https://github.com/auth0/express-openid-connect)** - Código fuente y Ejemplos
* **[Documentación de la API](https://auth0.github.io/express-openid-connect/)** - Referencia completa de la API
* **[Aplicación de ejemplo de Auth0 Express](https://github.com/auth0-samples/auth0-express-webapp-sample)** - Aplicación de ejemplo completa
* **[Comunidad de Auth0](https://community.auth0.com/)** - Obtén ayuda de la comunidad
