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

> La implementación en Node.js de la API para el escenario de arquitectura de aplicaciones de servidor + API

# Aplicaciones de servidor + API: implementación en Node.js para la API

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****ENMASCARADO*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

Como parte del [escenario de arquitectura de servidor + API](/es/docs/get-started/architecture-scenarios/server-application-api), implementaremos la API de Timesheets en Node.js. Consulta el escenario para obtener más información sobre la solución implementada.

El código fuente completo de la implementación de la API en Node.js está disponible en [este repositorio de GitHub](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-api/node).

<div id="step-1-define-the-api-endpoint">
  ## Paso 1. Define el endpoint de la API
</div>

Usaremos el framework de aplicaciones web [Express](http://expressjs.com/) para crear nuestra API de Node.js.

<div id="create-a-packagejson-file">
  ### Cree un archivo package.json
</div>

Cree una carpeta para su API, acceda a ella y ejecute `npm init`. Esto generará el archivo `package.json`.

Puede dejar la configuración predeterminada o cambiarla según le convenga.

El archivo `package.json` de nuestro ejemplo es el siguiente:

```json lines theme={null}
{
  "name": "timesheets-api",
  "version": "1.0.0",
  "description": "API used to add timesheet entries for employees and contractors",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/auth0-samples/auth0-pnp-timesheets.git"
  },
  "author": "Auth0",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/auth0-samples/auth0-pnp-timesheets/issues"
  },
  "homepage": "https://github.com/auth0-samples/auth0-pnp-timesheets#readme"
}
```

<div id="install-the-dependencies">
  ### Instale las dependencias
</div>

A continuación, debemos definir nuestras dependencias. Usaremos los siguientes módulos:

* **express**: Este módulo agrega el [framework web Express](https://expressjs.com/).
* **jwks-rsa**: Esta biblioteca recupera claves de firma RSA desde un endpoint JWKS (JSON Web Key Set). Mediante `expressJwtSecret`, podemos generar un proveedor de secretos que proporcionará la clave de firma correcta a `express-jwt` en función del `kid` del encabezado <Tooltip tip="JWT (JSON Web Token): formato estándar de ID Token (y, a menudo, de Token de acceso) que se usa para representar claims de forma segura entre dos partes." cta="Ver glosario" href="/es/docs/glossary?term=JWT">JWT</Tooltip>. Para obtener más información, consulte el [repositorio de GitHub de node-jwks-rsa](https://github.com/auth0/node-jwks-rsa).
* **express-jwt**: Este módulo le permite autenticar solicitudes HTTP mediante tokens JWT en sus aplicaciones de Node.js. Proporciona varias funciones que facilitan el trabajo con JWT. Para obtener más información, consulte el [repositorio de GitHub de express-jwt](https://github.com/auth0/express-jwt).
* **body-parser**: Este es un middleware de análisis del cuerpo para Node.js. Extrae por completo el cuerpo de un flujo de solicitud entrante y lo expone en `req.body` de una forma más fácil de usar. Para obtener más información y varias alternativas, consulte el repositorio de GitHub de body-parser.

Para instalar estas dependencias, ejecute lo siguiente:

```bash lines theme={null}
npm install express express-jwt jwks-rsa body-parser --save
```

<div id="implement-the-endpoint">
  ### Implementa el endpoint
</div>

Ve al directorio de tu API y crea un archivo `server.js`. Tu código debe:

* Configurar las dependencias.
* Habilitar el middleware para analizar el cuerpo de la solicitud.
* Implementar el endpoint.
* Iniciar el servidor de la API.

Esta es una implementación de ejemplo:

```javascript lines theme={null}
// establecer dependencias
const express = require('express');
const app = express();
const jwt = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const bodyParser = require('body-parser');

// habilitar el uso del middleware de análisis del cuerpo de la solicitud
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

// crear el endpoint de la API para subir hojas de horas
app.post('/timesheets/upload', function(req, res){
  res.status(201).send({message: "This is the POST /timesheets/upload endpoint"});
})

// iniciar el servidor de la API en localhost:8080
app.listen(8080);
```

Inicie su servidor API con `node server` y haga una solicitud HTTP POST a `localhost:8080/timesheets/upload`. Debería ver una respuesta JSON con el mensaje `This is the POST /timesheets/upload endpoint`.

Ahora ya tenemos el endpoint, pero cualquiera puede llamarlo. Continúe con el siguiente párrafo para ver cómo podemos solucionarlo.

<div id="step-2-secure-the-api-endpoint">
  ## Paso 2. Proteger el endpoint de la API
</div>

Para validar nuestro token, usaremos la función `jwt`, proporcionada por el [middleware express-jwt](https://github.com/auth0/express-jwt#usage), y el paquete `jwks-rsa` para obtener la clave pública de Auth0. Estas bibliotecas hacen lo siguiente:

1. `express-jwt` decodificará el token y pasará la solicitud, el encabezado y la carga útil a `jwksRsa.expressJwtSecret`.
2. `jwks-rsa` descargará entonces todas las claves de firma del endpoint JWKS y comprobará si alguna de ellas coincide con el `kid` del encabezado del JWT. Si ninguna de las claves de firma coincide con el `kid` recibido, se generará un error. Si hay coincidencia, pasaremos la clave de firma correcta a `express-jwt`.
3. `express-jwt` continuará con su propia lógica para validar la firma del token, la expiración, la `audience` y el `issuer`.

Los pasos que seguiremos en nuestro código son:

* Crear la función de middleware para validar el <Tooltip tip="Token de acceso: credencial de autorización, en forma de cadena opaca o JWT, utilizada para acceder a una API." cta="Ver glosario" href="/es/docs/glossary?term=access+token">token de acceso</Tooltip>.
* Habilitar el uso del middleware en nuestras rutas.

Este es también un buen momento para implementar la lógica para guardar los registros de horas en una base de datos local, o en cualquier otro mecanismo de almacenamiento que prefieras. Esta es nuestra implementación de ejemplo (se omite parte del código por brevedad):

export const codeExample = `// configurar dependencias: código omitido

// habilitar el middleware para analizar el cuerpo de la solicitud: código omitido

// Crear middleware para validar el JWT
const checkJwt = jwt({
  // Proporcionar dinámicamente una clave de firma en función del kid del encabezado y de las claves de firma proporcionadas por el endpoint JWKS.
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: \`https://{yourDomain}/.well-known/jwks.json\`
  }),

  // Validar la audiencia y el emisor.
  audience: process.env.AUTH0_AUDIENCE,
  issuer: \`https://{yourDomain}/\`,
  algorithms: ['RS256']
});

// crear el endpoint de la API de hojas de horas
app.post('/timesheets/upload', checkJwt, function(req, res){
  var timesheet = req.body;

  // Guardar la entrada de la hoja de horas en la base de datos...

  // enviar la respuesta
  res.status(201).send(timesheet);
})

// iniciar el servidor de la API en localhost:8080: código omitido`;

<AuthCodeBlock children={codeExample} language="javascript" />

Si iniciamos el servidor ahora y hacemos una solicitud HTTP POST a `localhost:8080/timesheets/upload`, deberíamos recibir el mensaje de error `Missing or invalid token` (lo cual es perfectamente normal, ya que no enviamos ningún token de acceso en la solicitud).

Para probar también el escenario correcto, necesitamos:

* Obtener un token de acceso. Para obtener más información sobre cómo hacerlo, consulta: [Obtener un token de acceso](/es/docs/get-started/architecture-scenarios/server-application-api#get-an-access-token)
* Invocar la API añadiendo un encabezado `Authorization` a la solicitud con el valor `Bearer ACCESS_TOKEN` (donde `ACCESS_TOKEN` es el valor del token que obtuvimos en el primer paso).

<div id="step-3-check-the-client-permissions">
  ## Paso 3. Verifique los permisos del cliente
</div>

En este paso, agregaremos a nuestra implementación la capacidad de comprobar si el cliente tiene permisos (o `scope`) para usar nuestro endpoint y subir una hoja de horas. En concreto, queremos asegurarnos de que el token tenga el `scope` correcto, que es `batch:upload`.

Para ello, usaremos el paquete de Node.js `express-jwt-authz`, así que agréguelo a su proyecto:

```bash lines theme={null}
npm install express-jwt-authz --save
```

Ahora es tan sencillo como añadir una llamada a `jwtAuthz(...)` a tu middleware para asegurarte de que el JWT contenga un scope determinado antes de ejecutar un endpoint concreto. Esta es nuestra implementación de ejemplo (se omite parte del código por brevedad):

```javascript lines theme={null}
// establecer dependencias - parte del código omitido
const jwtAuthz = require('express-jwt-authz');

// Crear middleware para verificar el JWT

// Habilitar el uso del middleware de análisis del cuerpo de la solicitud
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

// Endpoint de carga por lotes
app.post('/timesheets/upload', checkJwt, jwtAuthz(['batch:upload']), function(req, res){
  var timesheet = req.body;

  // Guardar la entrada de la hoja de horas en la base de datos...

  //enviar la respuesta
  res.status(201).send(timesheet);
});

// iniciar el servidor de API en localhost:8080 - código omitido
```

Si invocamos nuestra API con un token que no incluye este scope, deberíamos recibir el mensaje de error Forbidden con el código de estado HTTP `403`. Puede comprobarlo eliminando este scope de su API.

¡Eso es todo! ¡Ha terminado!
