Saltar al contenido principal

Use la IA para integrar Auth0

Si usa un asistente de programación con IA como Claude Code, Cursor o GitHub Copilot, puede añadir automáticamente la autenticación de Auth0 a su API en cuestión de minutos mediante agent skills.Instalar:
npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-fastify-api
Luego, pídale a su asistente de IA:
Add Auth0 JWT authentication to my Fastify API
Su asistente de IA creará automáticamente su API de Auth0, recuperará las credenciales, instalará @auth0/auth0-fastify-api, configurará el plugin y protegerá los endpoints de su API con validación de JWT. Documentación completa de agent skills →
Requisitos previos: Antes de comenzar, asegúrese de tener instalado lo siguiente:Verifique la instalación: node --version && npm --versionCompatibilidad de versiones de Fastify: Esta guía de inicio rápido funciona con Fastify 5.x y versiones posteriores.

Primeros pasos

Esta guía de inicio rápido muestra cómo proteger los endpoints de una API de Fastify con tokens de acceso JWT. Crearás una API segura que valida los tokens de acceso de Auth0 y concede acceso a recursos protegidos.
1

Crear un proyecto nuevo

Crea un directorio nuevo para tu API de Fastify e inicializa un proyecto de Node.js.
mkdir auth0-fastify-api && cd auth0-fastify-api
Inicializar el proyecto
npm init -y
Cree la estructura del proyecto
touch server.js .env
2

Instala el SDK de la API de Auth0 para Fastify

Instale las dependencias requeridas
npm install @auth0/auth0-fastify-api fastify dotenv
Actualiza tu package.json para agregar scripts de inicio:
package.json
{
  "name": "auth0-fastify-api",
  "version": "1.0.0",
  "type": "module",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js"
  },
  "dependencies": {
    "@auth0/auth0-fastify-api": "^1.2.0",
    "dotenv": "^16.3.1",
    "fastify": "^5.0.0"
  }
}
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:
# Instala Auth0 CLI (si aún no está instalado)
brew tap auth0/auth0-cli && brew install auth0

# Crea la API de Auth0
auth0 apis create \
  --name "My Fastify API" \
  --identifier https://my-fastify-api.example.com
Después de crearla, copia los valores de Identifier y dominio, y luego crea tu archivo .env:
.env
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
Este comando hará lo siguiente:
  1. Comprobará si has iniciado sesión (y te pedirá que lo hagas 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
Verifica que tu archivo .env exista: cat .env (Mac/Linux) o type .env (Windows)
4

Configurar el plugin de la API de Auth0

Cree su servidor Fastify y registre el complemento de la API de Auth0:
server.js
import 'dotenv/config';
import Fastify from 'fastify';
import fastifyAuth0Api from '@auth0/auth0-fastify-api';

const fastify = Fastify({ logger: true });
const port = process.env.PORT || 3001;

// Registrar el plugin de API de Auth0
await fastify.register(fastifyAuth0Api, {
  domain: process.env.AUTH0_DOMAIN,
  audience: process.env.AUTH0_AUDIENCE,
});

// Iniciar el servidor
fastify.listen({ port }, (err) => {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
  fastify.log.info(`API server running at http://localhost:${port}`);
});
Qué hace esto:
  • Registra el complemento de la API de Auth0 con tu dominio de Auth0 y la audiencia de la API
  • Configura la validación de JWT para las solicitudes entrantes
  • Pone el preHandler requireAuth() a disposición para proteger rutas
5

Crear rutas de API

Agrega rutas públicas y protegidas a tu archivo server.js:
server.js
import 'dotenv/config';
import Fastify from 'fastify';
import fastifyAuth0Api from '@auth0/auth0-fastify-api';

const fastify = Fastify({ logger: true });
const port = process.env.PORT || 3001;

// Registrar el plugin de Auth0 API
await fastify.register(fastifyAuth0Api, {
  domain: process.env.AUTH0_DOMAIN,
  audience: process.env.AUTH0_AUDIENCE,
});

// Ruta pública - no requiere autenticación
fastify.get('/api/public', async (request, reply) => {
  return {
    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
fastify.get('/api/private', {
  preHandler: fastify.requireAuth()
}, async (request, reply) => {
  return {
    message: 'Hello from a protected endpoint! You successfully authenticated.',
    user: request.user.sub,
    timestamp: new Date().toISOString(),
  };
});

// Ruta protegida - devuelve información del usuario desde el token
fastify.get('/api/profile', {
  preHandler: fastify.requireAuth()
}, async (request, reply) => {
  return {
    message: 'Your user profile from the access token',
    profile: request.user,
  };
});

// Iniciar servidor
fastify.listen({ port }, (err) => {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
  fastify.log.info(`API server running at http://localhost:${port}`);
});
Puntos clave:
  • Las rutas públicas no requieren autenticación
  • Las rutas protegidas usan preHandler: fastify.requireAuth() para exigir un JWT válido
  • request.user contiene las claims del JWT decodificado para las solicitudes autenticadas
  • La claim sub contiene el identificador único del usuario
6

Inicia tu API

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

Pruebe su 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 un token (debería fallar):
curl http://localhost:3001/api/private
Debería aparecer un error 401 Unauthorized:
{
  "error": "Unauthorized",
  "message": "No authorization token was found"
}
Para probar con un token válido, necesitas:
  1. Crear una aplicación cliente (web o móvil) que autentique usuarios
  2. Configurar el cliente para solicitar un token de acceso para tu API (mediante el parámetro audience)
  3. Usar ese token de acceso en el encabezado Authorization
Ejemplo con un token:
curl http://localhost:3001/api/private \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Punto de controlAhora deberías tener una API protegida. Tu 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 tu dominio de Auth0 y la audiencia
  4. Proporciona información del usuario a partir de los claims del token mediante request.user

Uso avanzado

Amplía la interfaz Token para añadir seguridad de tipos a los claims personalizados de tus tokens de acceso:
server.ts
import '@auth0/auth0-fastify-api';

// Amplía la interfaz Token con tus claims personalizados
declare module '@auth0/auth0-fastify-api' {
  interface Token {
    sub: string;
    permissions?: string[];
    'https://myapp.com/roles'?: string[];
    email?: string;
    email_verified?: boolean;
  }
}
Ahora TypeScript reconocerá tus claims personalizados:
server.ts
fastify.get('/api/profile', {
  preHandler: fastify.requireAuth()
}, async (request, reply) => {
  // TypeScript reconoce estas propiedades
  const userRoles = request.user['https://myapp.com/roles']; // string[] | undefined
  const permissions = request.user.permissions; // string[] | undefined
  const email = request.user.email; // string | undefined

  return {
    userId: request.user.sub,
    roles: userRoles || [],
    permissions: permissions || [],
    email: email,
  };
});
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.
Comprueba permisos específicos en el token de acceso:
server.js
// Middleware para comprobar un permiso específico
function requirePermission(permission) {
  return async (request, reply) => {
    const permissions = request.user.permissions || [];

    if (!permissions.includes(permission)) {
      return reply.status(403).send({
        error: 'Forbidden',
        message: `Missing required permission: ${permission}`
      });
    }
  };
}

// Ruta que requiere el permiso 'read:messages'
fastify.get('/api/messages', {
  preHandler: [
    fastify.requireAuth(),
    requirePermission('read:messages')
  ]
}, async (request, reply) => {
  return {
    messages: ['Message 1', 'Message 2', 'Message 3']
  };
});

// Ruta que requiere el permiso 'write:messages'
fastify.post('/api/messages', {
  preHandler: [
    fastify.requireAuth(),
    requirePermission('write:messages')
  ]
}, async (request, reply) => {
  return {
    message: 'Message created successfully',
    id: 'msg_123'
  };
});
Los permisos deben configurarse en la configuración de la API de Auth0 y concederse a los clientes. Más información sobre los permisos de API.
Implemente el control de acceso basado en roles mediante claims personalizados:
server.js
// Middleware para comprobar un rol específico
function requireRole(role) {
  return async (request, reply) => {
    const roles = request.user['https://myapp.com/roles'] || [];

    if (!roles.includes(role)) {
      return reply.status(403).send({
        error: 'Forbidden',
        message: `Missing required role: ${role}`
      });
    }
  };
}

// Ruta solo para administradores
fastify.get('/api/admin/users', {
  preHandler: [
    fastify.requireAuth(),
    requireRole('admin')
  ]
}, async (request, reply) => {
  return {
    users: [
      { id: 1, name: 'User 1' },
      { id: 2, name: 'User 2' }
    ]
  };
});

// Ruta para manager o admin
function requireAnyRole(...roles) {
  return async (request, reply) => {
    const userRoles = request.user['https://myapp.com/roles'] || [];
    const hasRole = roles.some(role => userRoles.includes(role));

    if (!hasRole) {
      return reply.status(403).send({
        error: 'Forbidden',
        message: `Missing required role. Need one of: ${roles.join(', ')}`
      });
    }
  };
}

fastify.get('/api/reports', {
  preHandler: [
    fastify.requireAuth(),
    requireAnyRole('admin', 'manager')
  ]
}, async (request, reply) => {
  return { reports: [] };
});
Los roles deben agregarse a los tokens mediante Auth0 Actions. Aprenda a agregar roles a los tokens.
Habilite CORS para permitir solicitudes desde aplicaciones web:
npm install @fastify/cors
server.js
import cors from '@fastify/cors';

await fastify.register(cors, {
  origin: ['http://localhost:3000', 'http://localhost:5173'], // URLs de su aplicación web
  credentials: true,
});
Para producción, especifique los orígenes exactos:
server.js
await fastify.register(cors, {
  origin: [
    'https://myapp.com',
    'https://www.myapp.com'
  ],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
});
Agregue un manejo de errores completo para los errores de autenticación:
server.js
// Manejador de errores personalizado
fastify.setErrorHandler((error, request, reply) => {
  fastify.log.error(error);

  // Manejar errores de validación de JWT
  if (error.statusCode === 401) {
    return reply.status(401).send({
      error: 'Unauthorized',
      message: error.message || 'Invalid or missing access token',
      code: 'UNAUTHORIZED'
    });
  }

  // Manejar errores de permisos/roles
  if (error.statusCode === 403) {
    return reply.status(403).send({
      error: 'Forbidden',
      message: error.message || 'Insufficient permissions',
      code: 'FORBIDDEN'
    });
  }

  // Manejar otros errores
  return reply.status(error.statusCode || 500).send({
    error: 'Internal Server Error',
    message: 'An unexpected error occurred',
    code: 'INTERNAL_ERROR'
  });
});

// Manejador para rutas no encontradas
fastify.setNotFoundHandler((request, reply) => {
  return reply.status(404).send({
    error: 'Not Found',
    message: `Route ${request.method} ${request.url} not found`,
    code: 'NOT_FOUND'
  });
});
Protege tu API frente a abusos mediante la limitación de tasa:
npm install @fastify/rate-limit
server.js
import rateLimit from '@fastify/rate-limit';

await fastify.register(rateLimit, {
  max: 100, // Número máximo de solicitudes
  timeWindow: '1 minute', // Ventana de tiempo
  errorResponseBuilder: (request, context) => {
    return {
      error: 'Too Many Requests',
      message: `Rate limit exceeded. Try again in ${context.after}`,
      retryAfter: context.after
    };
  }
});

// Aplica límites más estrictos a rutas específicas
fastify.get('/api/expensive-operation', {
  preHandler: fastify.requireAuth(),
  config: {
    rateLimit: {
      max: 10,
      timeWindow: '1 minute'
    }
  }
}, async (request, reply) => {
  return { result: 'expensive operation result' };
});

Solución de problemas

”No authorization token was found”

Problema: La API no puede encontrar el token de acceso en la solicitud.Soluciones:
  1. Asegúrate de que la cabecera 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)

“Invalid signature”

Problema: La firma del token no coincide.Soluciones:
  1. Verifica que AUTH0_DOMAIN coincida con el dominio que emitió el token
  2. Asegúrate de usar el algoritmo de firma RS256 (predeterminado)
  3. Comprueba que el token no se haya modificado

”Invalid audience”

Problema: La audiencia del token no coincide con tu API.Solución: La aplicación cliente debe solicitar un token con la audiencia correcta:
// En tu aplicación cliente
const token = await getAccessTokenSilently({
  authorizationParams: {
    audience: 'https://my-fastify-api.example.com' // Debe coincidir con el identificador de tu API
  }
});

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 @fastify/cors:
npm install @fastify/cors
import cors from '@fastify/cors';

await fastify.register(cors, {
  origin: 'http://localhost:3000', // La URL de tu frontend
  credentials: true
});

Próximos pasos

Ahora que tiene una API protegida, le recomendamos explorar lo siguiente:

Recursos