Saltar al contenido principal

Usa IA para integrar Auth0

Si usas un asistente de codificación con IA como Claude Code, Cursor o GitHub Copilot, puedes añadir autenticación de Auth0 a tu API automáticamente en minutos con agent skills.Instala:
npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-express-api
Luego pídele a tu asistente de IA:
Add Auth0 JWT authentication to my Express API
Tu asistente de IA creará automáticamente tu API de Auth0, recuperará las credenciales, instalará express-oauth2-jwt-bearer, configurará el middleware JWT y protegerá los endpoints de tu API mediante la validación de tokens. Documentación completa sobre agent skills →
Requisitos previos: Antes de comenzar, asegúrate de tener instalado lo siguiente:
  • Node.js 18 LTS o posterior (compatible con ^18.12.0 || ^20.2.0 || ^22.1.0 || ^24.0.0)
  • npm 8+ o yarn 1.22+ o pnpm 8+
Verifica la instalación: node --version && npm --versionCompatibilidad de versiones de Express: Esta guía de inicio rápido funciona con Express 4.x y Express 5.x.

Primeros pasos

Esta guía de inicio rápido muestra cómo proteger endpoints de API de Express.js mediante tokens de acceso JWT. Crearás una API segura que validará tokens de acceso de Auth0, protegerá rutas e implementará autorización basada en scope.
1

Crear un proyecto nuevo

Cree un directorio nuevo para su API de Express e inicialice un proyecto de Node.js.
mkdir auth0-express-api && cd auth0-express-api
Inicializa el proyecto
npm init -y
Cree la estructura del proyecto
touch server.js .env
2

Instala el SDK de express-oauth2-jwt-bearer

Instala las dependencias requeridas
npm install express express-oauth2-jwt-bearer dotenv
Añade scripts de inicio a tu package.json:
package.json
{
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js"
  }
}
3

Configura tu API de Auth0

A continuación, debes crear una nueva API en tu inquilino de Auth0 y agregar las variables de entorno a tu proyecto.Tienes dos opciones para configurar tu API de Auth0: usar un comando de la CLI o configurarla manualmente desde el Dashboard:
Ejecuta el siguiente comando en el directorio raíz de tu proyecto para crear una API de Auth0:
# Instalar Auth0 CLI (si aún no está instalado)
brew tap auth0/auth0-cli && brew install auth0

# Crear API de Auth0
auth0 apis create \
  --name "My Express API" \
  --identifier https://my-express-api.example.com
Este comando hará lo siguiente:
  1. Comprobar si has iniciado sesión (y pedirte que inicies sesión si es necesario)
  2. Crear una API de Auth0 con el identificador especificado
  3. Mostrar los detalles de la API, incluidos el dominio y el identificador
Después de crearla, copia los valores de Identifier y Domain, y luego crea tu archivo .env:
.env
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
Reemplaza YOUR_AUTH0_DOMAIN por el dominio de tu inquilino de Auth0 (por ejemplo, dev-abc123.us.auth0.com) y YOUR_API_IDENTIFIER por el identificador de tu API (por ejemplo, https://my-express-api.example.com).
Verifica que tu archivo .env exista: cat .env (Mac/Linux) o type .env (Windows)
4

Configure el middleware JWT

Cree su servidor Express y configure la validación de JWT:
server.js
require('dotenv').config();
const express = require('express');
const { auth } = require('express-oauth2-jwt-bearer');

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

// Configurar el middleware de validación JWT
const checkJwt = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
});

// Iniciar el servidor
app.listen(port, () => {
  console.log(`API server running at http://localhost:${port}`);
});
Qué hace esto:
  • Crea un middleware de validación de JWT con tu dominio de Auth0 y la audiencia de la API
  • Valida las claims iss y aud de los tokens de acceso entrantes
  • Hace que checkJwt esté disponible para proteger rutas individuales
5

Crear rutas de la API

Añade rutas públicas y protegidas a tu server.js:
server.js
require('dotenv').config();
const express = require('express');
const { auth, requiredScopes } = require('express-oauth2-jwt-bearer');

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

// Configurar el middleware de validación de JWT
const checkJwt = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
});

// Ruta pública - no requiere autenticación
app.get('/api/public', (req, res) => {
  res.json({
    message: 'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
    timestamp: new Date().toISOString(),
  });
});

// Ruta protegida - requiere un token de acceso válido
app.get('/api/private', checkJwt, (req, res) => {
  res.json({
    message: 'Hello from a protected endpoint! You successfully authenticated.',
    user: req.auth.payload.sub,
    timestamp: new Date().toISOString(),
  });
});

// Ruta protegida con scope - requiere el scope 'read:messages'
app.get('/api/private-scoped', checkJwt, requiredScopes('read:messages'), (req, res) => {
  res.json({
    message: 'Hello from a scoped endpoint! You have the required permission.',
    user: req.auth.payload.sub,
    scope: req.auth.payload.scope,
    timestamp: new Date().toISOString(),
  });
});

// Middleware de manejo de errores
app.use((err, req, res, next) => {
  const status = err.status || 500;
  const message = err.message || 'Internal Server Error';

  res.status(status).json({
    error: err.code || 'server_error',
    message: status === 401 ? 'Authentication required' : message,
  });
});

// Iniciar el servidor
app.listen(port, () => {
  console.log(`API server running at http://localhost:${port}`);
});
Puntos clave:
  • Las rutas públicas no requieren autenticación
  • Las rutas protegidas usan el middleware checkJwt para exigir un JWT válido
  • Las rutas con alcances usan requiredScopes() para exigir permisos específicos en el token
  • req.auth.payload contiene las claims del JWT decodificado para las solicitudes autenticadas
  • La claim sub contiene el identificador único del usuario
6

Ejecute la API

Inicia el servidor de desarrollo:
npm run dev
Tu API ya se está ejecutando en http://localhost:3001.
La opción --watch en Node.js 18+ reinicia automáticamente el servidor cuando cambian los archivos.
7

Pruebe la API

Pruebe el endpoint público (no requiere autenticación):
curl http://localhost:3001/api/public
Deberías ver:
{
  "message": "Hello from a public endpoint! You don't need to be authenticated to see this.",
  "timestamp": "2024-01-15T10:30:00.000Z"
}
Pruebe el endpoint protegido sin token (debería fallar):
curl http://localhost:3001/api/private
Debería ver un error 401 Unauthorized:
{
  "error": "unauthorized",
  "message": "Authentication required"
}
Para hacer una prueba con un token válido:
  1. Ve a Auth0 DashboardApplicationsAPIs
  2. Selecciona tu API → pestaña Test
  3. Copia el token de acceso generado
Prueba tu endpoint protegido:
curl http://localhost:3001/api/private \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Deberías ver:
{
  "message": "Hello from a protected endpoint! You successfully authenticated.",
  "user": "auth0|abc123...",
  "timestamp": "2024-01-15T10:30:00.000Z"
}
Punto de verificaciónAhora debería tener una API protegida. Su API:
  1. Acepta solicitudes a endpoints públicos sin autenticación
  2. Rechaza solicitudes a endpoints protegidos sin un token válido
  3. Valida los tokens JWT con respecto a su dominio y audiencia de Auth0
  4. Proporciona información del usuario a partir de los claims del token mediante req.auth.payload

Uso avanzado

Los alcances permiten un control de acceso granular. Puede exigir alcances específicos para distintos endpoints.Configure los alcances en Auth0:
  1. En el Auth0 Dashboard, vaya a ApplicationsAPIs → Your API
  2. Vaya a la pestaña Permissions
  3. Agregue permisos como read:messages, write:messages, admin:access
Proteja las rutas con alcances:
server.js
const { auth, requiredScopes } = require('express-oauth2-jwt-bearer');

// Requiere el scope 'read:messages'
app.get('/api/messages', checkJwt, requiredScopes('read:messages'), (req, res) => {
  res.json({
    messages: [
      { id: 1, text: 'Hello!' },
      { id: 2, text: 'World!' },
    ],
  });
});

// Requiere el scope 'admin:access'
app.get('/api/admin', checkJwt, requiredScopes('admin:access'), (req, res) => {
  res.json({
    message: 'Admin access granted',
    userId: req.auth.payload.sub,
  });
});
Si una solicitud no incluye el alcance requerido, la API devuelve 403 Forbidden con un error insufficient_scope. Asegúrese de que la aplicación cliente solicite los alcances correctos al obtener un token de acceso.
Además de los alcances, puede validar claims personalizados en la carga útil del JWT:
server.js
const { auth, claimEquals, claimIncludes, claimCheck } = require('express-oauth2-jwt-bearer');

// Requiere un valor exacto del claim
app.get('/api/org/:orgId',
  checkJwt,
  claimEquals('org_id', 'org_123'),
  (req, res) => {
    res.json({ message: 'Organization access granted' });
  }
);

// Requiere que el claim incluya todos los valores especificados
app.get('/api/roles',
  checkJwt,
  claimIncludes('roles', 'editor', 'viewer'),
  (req, res) => {
    res.json({ message: 'Role check passed' });
  }
);

// Lógica de validación de claims personalizados
app.get('/api/premium',
  checkJwt,
  claimCheck((claims) => {
    return claims.subscription === 'premium' && claims.verified === true;
  }),
  (req, res) => {
    res.json({ message: 'Premium feature access granted' });
  }
);
Los claims personalizados deben usar URL con espacio de nombres (por ejemplo, https://myapp.com/roles) a menos que sean claims estándar de OIDC. Más información sobre los claims personalizados.
Permita acceso autenticado y anónimo a la misma ruta:
server.js
const optionalAuth = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
  authRequired: false,
});

app.get('/api/feed', optionalAuth, (req, res) => {
  if (req.auth) {
    res.json({
      message: `Welcome back, ${req.auth.payload.sub}!`,
      personalizedContent: true,
    });
  } else {
    res.json({
      message: 'Welcome, guest!',
      personalizedContent: false,
    });
  }
});
Habilite CORS para permitir solicitudes desde aplicaciones web:
npm install cors
server.js
const cors = require('cors');

app.use(cors({
  origin: ['http://localhost:3000', 'http://localhost:5173'],
  allowedHeaders: ['Authorization', 'Content-Type'],
  exposedHeaders: ['WWW-Authenticate'],
}));
Para producción, especifique los orígenes exactos:
server.js
app.use(cors({
  origin: [
    'https://myapp.com',
    'https://www.myapp.com'
  ],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));
Añada un manejo exhaustivo de los errores de autenticación:
server.js
const { UnauthorizedError, InvalidTokenError, InsufficientScopeError } = require('express-oauth2-jwt-bearer');

app.use((err, req, res, next) => {
  if (err instanceof InsufficientScopeError) {
    return res.status(403).json({
      error: 'forbidden',
      message: 'You do not have permission to access this resource',
      required_scopes: err.requiredScopes,
    });
  }

  if (err instanceof InvalidTokenError) {
    return res.status(401).json({
      error: 'invalid_token',
      message: 'The provided token is invalid or expired',
    });
  }

  if (err instanceof UnauthorizedError) {
    return res.status(401).set(err.headers).json({
      error: 'unauthorized',
      message: 'Authentication required',
    });
  }

  next(err);
});
Para proyectos de TypeScript, instale las definiciones de tipos y configure el proyecto:
npm install -D typescript @types/express @types/node
Cree server.ts:
server.ts
import 'dotenv/config';
import express, { Request, Response, NextFunction } from 'express';
import { auth, requiredScopes, UnauthorizedError } from 'express-oauth2-jwt-bearer';

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

const checkJwt = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
});

app.get('/api/public', (req: Request, res: Response) => {
  res.json({ message: 'Public endpoint - no authentication required' });
});

app.get('/api/private', checkJwt, (req: Request, res: Response) => {
  res.json({
    message: 'Private endpoint',
    user: req.auth?.payload.sub,
  });
});

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  if (err instanceof UnauthorizedError) {
    res.status(err.status).set(err.headers).json({
      error: err.code || 'unauthorized',
      message: 'Authentication required',
    });
  } else {
    res.status(500).json({
      error: 'server_error',
      message: 'Internal Server Error',
    });
  }
});

app.listen(port, () => {
  console.log(`API server running at http://localhost:${port}`);
});
Añada un tsconfig.json:
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "./dist"
  },
  "include": ["*.ts"]
}
Ejecútelo con: npx ts-node server.ts

Resolución de problemas

”No authorization token was found”

Problema: La API no encuentra el token de acceso en la solicitud.Soluciones:
  1. Asegúrate de que el encabezado Authorization esté presente: Authorization: Bearer YOUR_TOKEN
  2. Comprueba que “Bearer” esté incluido antes del token
  3. Verifica que el token no haya expirado

”Invalid token” o “jwt malformed”

Problema: El formato del token no es válido.Soluciones:
  1. Asegúrate de que estás usando un token de acceso, no un token de ID
  2. El token debe obtenerse con el parámetro audience de tu API
  3. Comprueba que el token sea un JWT válido (debe tener tres partes separadas por puntos)

Valor inesperado de “iss” o “aud”

Problema: El emisor o la audiencia del token no coinciden con tu configuración.Soluciones:
  1. Decodifica tu token en jwt.io
  2. Comprueba que el claim iss coincida con https://YOUR_AUTH0_DOMAIN/ (ten en cuenta la barra diagonal final)
  3. Comprueba que el claim aud coincida exactamente con tu AUTH0_AUDIENCE
  4. Verifica los valores de tu .env:
AUTH0_DOMAIN=dev-abc123.us.auth0.com
AUTH0_AUDIENCE=https://my-express-api.example.com

“You must provide an issuerBaseURL” o “audience is required”

Problema: Las variables de entorno no se están cargando.Soluciones:
  1. Asegúrate de que el archivo .env exista en la raíz de tu proyecto
  2. Verifica que dotenv esté instalado: npm install dotenv
  3. Agrega require('dotenv').config() al principio de tu archivo del servidor
  4. Comprueba que los nombres de las variables coincidan exactamente (distinguen entre mayúsculas y minúsculas)

401 Unauthorized en todas las solicitudes

Posibles causas:
  • El token ha expirado
  • La audiencia no coincide
  • El emisor no coincide
Pasos de depuración:
  1. Decodifica tu token en jwt.io
  2. Comprueba que el claim exp no haya vencido
  3. Verifica que el claim aud coincida exactamente con tu AUTH0_AUDIENCE
  4. Verifica que el claim iss sea https://{AUTH0_DOMAIN}/
  5. Asegúrate de que el formato del encabezado Authorization sea Bearer YOUR_TOKEN (con espacio)

403 Forbidden con “insufficient_scope”

Problema: El token no tiene los alcances requeridos.Soluciones:
  1. Verifica que los alcances estén definidos en tu API de Auth0 (Dashboard → ApplicationsAPIsPermissions)
  2. Solicita los alcances al obtener el token
  3. Comprueba que el claim scope del token incluya los alcances requeridos

Errores de CORS en el navegador

Problema: El navegador bloquea las solicitudes a la API debido a la política de CORS.Solución: Instala y configura cors:
npm install cors
const cors = require('cors');

app.use(cors({
  origin: 'http://localhost:3000',
}));

Próximos pasos

Ahora que ya tiene una API protegida, considere explorar lo siguiente:

Recursos