Saltar al contenido principal
Este documento forma parte del escenario de Arquitectura móvil + API y explica cómo implementar la API en Node.js. El código fuente completo de la implementación de la API en Node.js está disponible en este repositorio de GitHub. Consulte el escenario para obtener más información sobre la solución implementada.
Esta implementación usa el framework web Express para crear una API de Node.js.
Crear un archivo package.json
Cree una carpeta para su API, acceda a ella y ejecute npm init. Esto configura el archivo package.json.Deje la configuración predeterminada o cámbiela según le convenga.El archivo package.json de nuestro ejemplo es similar al siguiente:
{
  "name": "timesheets-api",
  "version": "1.0.0",
  "description": "API used to add timesheet entries for employees and contractors",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "body-parser": "^1.20.0",
    "cors": "^2.8.5",
    "express": "^4.18.0",
    "express-oauth2-jwt-bearer": "^1.6.0"
  },
  "author": "Auth0",
  "license": "MIT"
}
Instala las dependencias
A continuación, configura las dependencias con los siguientes módulos:
  • express: Este módulo añade el framework de aplicaciones web Express.
  • cors: Este módulo añade compatibilidad con CORS, lo cual es necesario porque se llama a la API desde una aplicación de una sola página que se ejecuta en un dominio diferente dentro de un navegador web.
  • jwks-rsa: Esta biblioteca recupera claves de firma RSA desde un endpoint de JWKS (JSON Web Key Set). Con expressJwtSecret, podemos generar un proveedor de secretos que proporciona la clave de firma correcta a express-jwt en función del kid del encabezado del JWT. Para obtener más información, consulta el repositorio de GitHub de node-jwks-rsa.
  • express-jwt: Este módulo autentica solicitudes HTTP mediante tokens JWT en tus aplicaciones de Node.js. Proporciona varias funciones que facilitan el trabajo con JWT. Para obtener más información, consulta el repositorio de GitHub de express-jwt.
  • body-parser: Este es un middleware de análisis del cuerpo de solicitudes para Node.js. Extrae todo el contenido del cuerpo de un flujo de solicitud entrante y lo expone en req.body de una forma más fácil de usar.
Para instalar estas dependencias, ejecuta lo siguiente:
npm install express cors express-jwt jwks-rsa body-parser express-jwt-authz --save
Implementa los endpoints
Ve al directorio de tu API y crea un archivo server.js. Tu código debe:
  • Instalar las dependencias.
  • Implementar el endpoint o los endpoints.
  • Iniciar el servidor de la API.
Esta es una implementación de ejemplo:
const express = require('express');
const app = express();
const { expressjwt: jwt } = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const cors = require('cors');
const bodyParser = require('body-parser');

// Habilitar CORS
app.use(cors());

// 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 de hojas de tiempo
app.post('/timesheets', function(req, res){
  res.status(201).send({message: "This is the POST /timesheets endpoint"});
})

// Iniciar el servidor de la API en localhost:8080
app.listen(8080);
Inicie su servidor de API con node server y haga una solicitud HTTP POST a localhost:8080/timesheets. Debería ver una respuesta JSON con el mensaje This is the POST /timesheets endpoint.Ahora ya tenemos nuestro endpoint, pero cualquiera puede llamarlo. Continúe con el siguiente paso para ver cómo podemos corregir esto.
Para validar nuestro token, use la función jwt, proporcionada por el middleware express-jwt, y jwks-rsa para recuperar nuestro secreto. Las bibliotecas hacen lo siguiente:
  1. express-jwt decodifica el token y pasa la solicitud, el encabezado y la carga útil a jwksRsa.expressJwtSecret.
  2. jwks-rsa descarga todas las claves de firma del endpoint JWKS y comprueba si alguna 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, pasa la clave de firma correcta a express-jwt.
  3. express-jwt continúa con su propia lógica para validar la firma del token, la expiración, audience y el issuer.
Los pasos que seguiremos en nuestro código son:
  • Crear la función de middleware para validar el token de acceso.
  • Habilitar el uso del middleware en nuestras rutas.
También puede escribir código para guardar realmente la hoja de horas en una base de datos. Esta es nuestra implementación de ejemplo (se omite parte del código por brevedad):Si iniciamos nuestro servidor ahora y hacemos una solicitud HTTP POST a localhost:8080/timesheets, deberíamos obtener el mensaje de error Missing or invalid token (lo cual es correcto, ya que no enviamos un token de acceso en nuestra solicitud).Para probar también el caso en que funciona correctamente, necesitamos:
  • Obtener un token de acceso. Para obtener más detalles sobre cómo hacerlo, consulte: Get an Access Token.
  • Invocar la API agregando a la solicitud un encabezado Authorization con el valor Bearer ACCESS_TOKEN (donde ACCESS_TOKEN es el valor del token que recuperamos en el primer paso).
En este paso, agregamos la capacidad de comprobar si la aplicación tiene permisos (o alcances) y de usar nuestro endpoint para crear una hoja de horas. En particular, queremos asegurarnos de que el token tenga el scope correcto, que es batch:upload.Para ello, usamos el paquete de Node.js express-jwt-authz, así que agrégalo a tu proyecto:
npm install express-jwt-authz --save
Ahora, agregue una llamada a jwtAuthz(...) en su middleware para asegurarse de que el JWT contenga un scope determinado para poder ejecutar un endpoint concreto.Agregamos una dependencia adicional. La biblioteca express-jwt-authz, que se usa junto con express-jwt, valida el JWT y garantiza que incluya los permisos correctos para llamar al endpoint deseado. Para obtener más información, consulte el repositorio de GitHub de express-jwt-authz.Esta es nuestra implementación de ejemplo (se omite parte del código por brevedad):
// establecer dependencias - parte del código omitido
const jwtAuthz = require('express-jwt-authz');

// Habilitar CORS - código omitido

// Crear middleware para verificar el JWT - código omitido

// Habilitar el uso del middleware de análisis del cuerpo de la solicitud - código omitido

// crear el endpoint de la API de hojas de tiempo
app.post('/timesheets', checkJwt, jwtAuthz(['create:timesheets'], { customUserKey: 'auth' }), function(req, res){
  var timesheet = req.body;

  // Guardar la hoja de tiempo 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
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. Puedes comprobarlo eliminando este scope de tu API.
El middleware express-jwt que se utiliza para validar el JWT también asigna req.user con la información contenida en el JWT. Si desea usar el claim sub para identificar al usuario de forma única, puede usar req.user.sub. Para la aplicación de registro de horas, queremos usar la dirección de correo electrónico del usuario como identificador único.
Crear una Action
Primero, cree una nueva Action que agregará la dirección de correo electrónico del usuario al token de acceso.
  1. Vaya a Auth0 Dashboard > Actions > Library y seleccione Build Custom.
  2. Introduzca un Nombre descriptivo para su Action (por ejemplo, Add email to access token), seleccione el trigger Login / Post Login y seleccione Create.
  3. Busque el editor de código de Actions, copie el siguiente código JavaScript en él y seleccione Save Draft para guardar los cambios:
    exports.onExecutePostLogin = async (event, api) => {
      const namespace = 'https://my-app.example.com';
      api.accessToken.setCustomClaim(`${namespace}/email`, event.user.email);
    }
    
    El namespace se utiliza para garantizar que el claim tenga un nombre único que no entre en conflicto con los claims estándar de OIDC ni con los servicios internos. Para obtener más información sobre las restricciones y directrices de los claims con y sin espacio de nombres, lea Create Custom Claims.
  4. En la barra lateral del editor de código de Actions, seleccione Test (icono de reproducción) y luego seleccione Run para probar su código.
  5. Cuando la Action esté lista para publicarse, seleccione Deploy.
Agregar su Action al trigger Post-Login
A continuación, agregue la Action que creó al trigger Post-Login. Para obtener información sobre cómo adjuntar Actions a triggers, lea Write Your First Action.
Recuperar el identificador único
Por último, desde su API, recupere el valor del claim desde req.auth. Use ese valor como identificador único del usuario para asociarlo con las entradas de registro de horas.
app.get('/timesheets', checkJwt, jwtAuthz(['read:timesheets'], { customUserKey: 'auth' }), function(req, res) {
  var timesheet = req.body;

  // Asociar la entrada de la hoja de horas con el usuario actual
  var userId = req.auth['https://api.exampleco.com/email'];
  timesheet.user_id = userId;

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

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