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

# Protege tu API de Express.js

> Esta guía muestra cómo proteger los endpoints de una API de Express.js mediante tokens de acceso JWT con el SDK express-oauth2-jwt-bearer.

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

<HowToSchema />

<Accordion title="Usa IA para integrar Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  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](https://agentskills.io/home).

  **Instala:**

  ```bash theme={null}
  npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-express-api
  ```

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

  ```text theme={null}
  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 →](/es/docs/quickstart/agent-skills)
</Accordion>

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

  * **[Node.js](https://nodejs.org/en/download)** 18 LTS o posterior (compatible con `^18.12.0 || ^20.2.0 || ^22.1.0 || ^24.0.0`)
  * **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 8+ o **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ o **[pnpm](https://pnpm.io/installation)** 8+

  Verifica la instalación: `node --version && npm --version`

  **Compatibilidad de versiones de Express:** Esta guía de inicio rápido funciona con **Express 4.x** y **Express 5.x**.
</Note>

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

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.

<Steps>
  <Step title="Crear un proyecto nuevo" stepNumber={1}>
    Cree un directorio nuevo para su API de Express e inicialice un proyecto de Node.js.

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

    Inicializa el proyecto

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

    Cree la estructura del proyecto

    ```shellscript theme={null}
    touch server.js .env
    ```
  </Step>

  <Step title="Instala el SDK de express-oauth2-jwt-bearer" stepNumber={2}>
    Instala las dependencias requeridas

    ```shellscript theme={null}
    npm install express express-oauth2-jwt-bearer dotenv
    ```

    Añade scripts de inicio a tu `package.json`:

    ```json package.json theme={null}
    {
      "scripts": {
        "start": "node server.js",
        "dev": "node --watch server.js"
      }
    }
    ```
  </Step>

  <Step title="Configura tu API de Auth0" stepNumber={3}>
    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:

    <Tabs>
      <Tab title="CLI">
        Ejecuta el siguiente comando en el directorio raíz de tu proyecto para crear una API de Auth0:

        <CodeGroup>
          ```shellscript Mac theme={null}
          # 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
          ```

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

          # Crear API de Auth0
          auth0 apis create `
            --name "My Express API" `
            --identifier https://my-express-api.example.com
          ```
        </CodeGroup>

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

        Después de crearla, copia los valores de **Identifier** y **Domain**, y luego crea tu archivo `.env`:

        ```bash .env theme={null}
        AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
        AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
        ```

        <Note>
          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`).
        </Note>
      </Tab>

      <Tab title="Dashboard">
        1. Ve al [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Ve a **Applications** → **APIs** → **Create API**
        3. Introduce un nombre para tu API (por ejemplo, "My Express API")
        4. Define el **Identifier** (por ejemplo, `https://my-express-api.example.com`)
           * Esta es la audiencia de tu API y debe tener un formato de URL válido
           * No es necesario que sea una URL real; es solo un identificador
        5. Deja **Signing Algorithm** como **RS256**
        6. Haz clic en **Create**
        7. Copia el valor de **Identifier** de la pestaña **Settings**

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

        ```bash .env theme={null}
        AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
        AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
        ```

        <Note>
          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 en el dashboard (por ejemplo, `https://my-express-api.example.com`).
        </Note>
      </Tab>
    </Tabs>

    <Tip>
      Verifica que tu archivo `.env` exista: `cat .env` (Mac/Linux) o `type .env` (Windows)
    </Tip>
  </Step>

  <Step title="Configure el middleware JWT" stepNumber={4}>
    Cree su servidor Express y configure la validación de JWT:

    ```javascript server.js {1-3,6-7,10-13} lines theme={null}
    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
  </Step>

  <Step title="Crear rutas de la API" stepNumber={5}>
    Añade rutas públicas y protegidas a tu `server.js`:

    ```javascript server.js expandable lines theme={null}
    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
  </Step>

  <Step title="Ejecute la API" stepNumber={6}>
    Inicia el servidor de desarrollo:

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

    Tu API ya se está ejecutando en [http://localhost:3001](http://localhost:3001).

    <Info>
      La opción `--watch` en Node.js 18+ reinicia automáticamente el servidor cuando cambian los archivos.
    </Info>
  </Step>

  <Step title="Pruebe la API" stepNumber={7}>
    Pruebe el endpoint público (no requiere autenticación):

    ```bash theme={null}
    curl http://localhost:3001/api/public
    ```

    Deberías ver:

    ```json theme={null}
    {
      "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):

    ```bash theme={null}
    curl http://localhost:3001/api/private
    ```

    Debería ver un error 401 Unauthorized:

    ```json theme={null}
    {
      "error": "unauthorized",
      "message": "Authentication required"
    }
    ```

    Para hacer una prueba con un token válido:

    1. Ve a [Auth0 Dashboard](https://manage.auth0.com/) → **Applications** → **APIs**
    2. Selecciona tu API → pestaña **Test**
    3. Copia el token de acceso generado

    Prueba tu endpoint protegido:

    ```bash theme={null}
    curl http://localhost:3001/api/private \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
    ```

    Deberías ver:

    ```json theme={null}
    {
      "message": "Hello from a protected endpoint! You successfully authenticated.",
      "user": "auth0|abc123...",
      "timestamp": "2024-01-15T10:30:00.000Z"
    }
    ```
  </Step>
</Steps>

<Check>
  **Punto de verificación**

  Ahora 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`
</Check>

***

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

<Accordion title="Autorización basada en alcances">
  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](https://manage.auth0.com/), vaya a **Applications** → **APIs** → Your API
  2. Vaya a la pestaña **Permissions**
  3. Agregue permisos como `read:messages`, `write:messages`, `admin:access`

  **Proteja las rutas con alcances:**

  ```javascript server.js theme={null}
  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,
    });
  });
  ```

  <Note>
    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.
  </Note>
</Accordion>

<Accordion title="Validación de claims personalizados">
  Además de los alcances, puede validar claims personalizados en la carga útil del JWT:

  ```javascript server.js theme={null}
  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' });
    }
  );
  ```

  <Note>
    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](https://auth0.com/docs/secure/tokens/json-web-tokens/create-custom-claims).
  </Note>
</Accordion>

<Accordion title="Autenticación opcional (rutas públicas/privadas mixtas)">
  Permita acceso autenticado y anónimo a la misma ruta:

  ```javascript server.js theme={null}
  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,
      });
    }
  });
  ```
</Accordion>

<Accordion title="Configuración de CORS">
  Habilite CORS para permitir solicitudes desde aplicaciones web:

  ```bash theme={null}
  npm install cors
  ```

  ```javascript server.js theme={null}
  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:

  ```javascript server.js theme={null}
  app.use(cors({
    origin: [
      'https://myapp.com',
      'https://www.myapp.com'
    ],
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
  }));
  ```
</Accordion>

<Accordion title="Gestión personalizada de errores">
  Añada un manejo exhaustivo de los errores de autenticación:

  ```javascript server.js theme={null}
  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);
  });
  ```
</Accordion>

<Accordion title="Compatibilidad con TypeScript">
  Para proyectos de TypeScript, instale las definiciones de tipos y configure el proyecto:

  ```bash theme={null}
  npm install -D typescript @types/express @types/node
  ```

  Cree `server.ts`:

  ```typescript server.ts theme={null}
  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`:

  ```json tsconfig.json theme={null}
  {
    "compilerOptions": {
      "target": "ES2020",
      "module": "commonjs",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "outDir": "./dist"
    },
    "include": ["*.ts"]
  }
  ```

  Ejecútelo con: `npx ts-node server.ts`
</Accordion>

***

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

<AccordionGroup>
  <Accordion title="Problemas comunes y soluciones">
    ### "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](https://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`:

    ```bash theme={null}
    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](https://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 → **Applications** → **APIs** → **Permissions**)
    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`:

    ```bash theme={null}
    npm install cors
    ```

    ```javascript theme={null}
    const cors = require('cors');

    app.use(cors({
      origin: 'http://localhost:3000',
    }));
    ```
  </Accordion>
</AccordionGroup>

***

<div id="next-steps">
  ## Próximos pasos
</div>

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

* **[Control de acceso basado en roles](https://auth0.com/docs/manage-users/access-control/rbac)** - Implemente permisos granulares
* **[Prácticas recomendadas para la autorización de API](https://auth0.com/docs/secure/tokens/access-tokens)** - Conozca las prácticas recomendadas para los tokens de acceso
* **[Supervise su API](https://auth0.com/docs/deploy-monitor/logs)** - Configure el registro y la supervisión
* **[Comunidad de Auth0](https://community.auth0.com/)** - Obtenga ayuda de la comunidad

***

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

* **[express-oauth2-jwt-bearer GitHub](https://github.com/auth0/node-oauth2-jwt-bearer/tree/main/packages/express-oauth2-jwt-bearer)** - Código fuente y ejemplos
* **[Express.js Documentation](https://expressjs.com/)** - Más información sobre Express
* **[Auth0 API Authentication](https://auth0.com/docs/secure/tokens/access-tokens)** - Comprenda los tokens de acceso
* **[JWT.io](https://jwt.io/)** - Depure y decodifique JWT
