Saltar al contenido principal

Usa IA para integrar Auth0

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.Instalar:
npx skills add https://github.com/auth0/agent-skills --skill auth0-express
Luego, pídele a tu asistente de IA:
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 →
Requisitos previos: Antes de comenzar, asegúrate de tener instalado lo siguiente:
  • Node.js 18 LTS o una versión posterior
  • npm 10+ o yarn 1.22+
  • 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.

Primeros pasos

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.

1. Cree un proyecto nuevo

Cree un nuevo directorio para su aplicación Express e inicialice un proyecto de Node.js.
mkdir auth0-express && cd auth0-express
npm init -y
Crea la estructura del proyecto:
touch index.js .env

2. Instala el SDK de Auth0 para Express

Instala express-openid-connect junto con Express y dotenv para gestionar las variables de entorno.
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:
npm install --save-dev nodemon
Actualiza tu package.json para añadir scripts de inicio: 📁 package.json
{
  "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"
  }
}

3. Configura tu aplicación de Auth0

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:
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:
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):
$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
Si aún no instalaste CLI de Auth0, ejecuta:
brew tap auth0/auth0-cli && brew install auth0
Luego, autentícate con auth0 login.

4. Configura el middleware

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

5. Cree rutas de inicio de sesión, cierre de sesión y perfil

Ahora agregue rutas para mostrar enlaces para iniciar y cerrar sesión, y una página de perfil protegida. 📁 index.js
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)

6. Ejecuta la aplicación

Inicia el servidor de desarrollo:
npm run dev
Abre http://localhost:3000 en tu navegador.
VerificaciónAhora 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

Uso avanzado

Utilice el middleware requiresAuth() para proteger las rutas individuales que requieren autenticación:
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:
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
Para llamar a APIs externas que requieren un token de acceso, configure el SDK para solicitar uno:📁 index.js (configuración actualizada)
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:
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:
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' });
  }
});
Para obtener tokens de actualización, añade offline_access a tu scope:
scope: 'openid profile email offline_access read:data',
Proteja las rutas según los claim del usuario (roles, permisos, etc.):
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');
});
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.
Para entornos de producción o si ejecuta varias instancias del servidor, use un almacén de sesiones personalizado:
npm install redis connect-redis
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
Agrega un manejo adecuado de los errores de autenticación:
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',
  });
});

Solución de problemas

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:
// ✅ 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:
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
// 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,
});

Siguientes pasos

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

Recursos