Claves de API y servicios externos — qué protege una clave y los webhooks

Este artículo forma parte del curso Fundamentos de informática, que construye desde cero los conocimientos prácticos de informática que necesitas como mínimo para programar y hacer vibe coding.
Una clave de API es una cadena que indica de quién es esa llamada. Con diagramas comprobamos dónde puedes guardarla y en qué dirección va un webhook, la solicitud que el servicio externo envía a tu servidor.

Este artículo trata dos cosas: la clave de API que usas al llamar a un servicio externo y el webhook que el servicio externo llama desde su lado.

Verás dónde se emite una clave, qué indica esa cadena y dónde ponerla para que nadie más pueda leerla.

  • Dónde emites una clave de API y en qué parte de la llamada la añades
  • Que una clave es una cadena que indica de quién es la llamada y su relación con el cobro por uso
  • Dónde se puede guardar una clave y qué pasa si la escribes en un sitio que llega al navegador
  • El webhook que se llama desde el lado del servicio externo y la comprobación de la firma

La clave de API se emite en el panel de control del servicio que usas

Para llamar a un servicio externo, primero recibes del proveedor una clave de API (API key: una cadena que le indica al proveedor de qué usuario es la llamada).

No es un valor que decidas tú: lo emite y te lo entrega el servicio que usas.

Ya sean pagos, mapas o generación de texto, la secuencia registrarte, emitir una clave y ponerla en tu propio servidor no cambia.

Desde emitir una clave de API hasta ponerla en my-app
El sitio web delservicioCrear una cuentaQuedas registradocomo usuarioSu panel de controlEmitir unaclave nuevaRecibes unacadena largaTu propio servidorEscribirla en .envPuedes añadirlaa las llamadas
Se avanza de arriba abajo. A la izquierda dónde trabajas, en el centro qué haces y a la derecha lo que obtienes ahí. La clave se crea en el panel del proveedor, y se guarda dentro de tu propio servidor.

Copia la cadena emitida en ese mismo momento y ponla en el archivo .env de tu propio servidor.

Muchos servicios externos funcionan con cobro por uso (pagas solo por lo que usas) y facturan según el número de llamadas y el volumen de datos enviados y recibidos.

Si una clave sale fuera, las llamadas que hagan otros también entran en la factura del dueño.

La clave de API es una cadena que indica de qué usuario es la llamada

La API de un servicio de pagos es una URL pública, así que necesita una forma de saber de quién es la llamada que le llega.

El sitio donde se añade no es la URL, sino la cabecera de la solicitud (request header: la parte que, aparte del cuerpo, enumera en pares de nombre y valor cosas como el remitente y el formato).

Una solicitud que my-app envía al servicio de pagos
Una solicitud enviada por my-app
Línea 1 — método y URL
  • POST https://api.pay.example.com/v1/charges
  • Solo dice adónde va y a qué
Desde la línea 2 — cabeceras de la solicitud
  • La clave de API se escribe aquí
  • Authorization: Bearer sk_live_a1b2
  • Un par de nombre y valor por línea
Tras una línea en blanco — el cuerpo
  • Los datos que envías, en JSON
  • Suele ir vacío en llamadas que solo consultan
El marco exterior es una solicitud. Si pones la clave en la URL queda registrada en el proveedor y en tu propio servidor, así que va en la cabecera del centro.

La segunda línea del marco central es la línea donde va la clave.

Authorization es el nombre de la cabecera, Bearer es la palabra que indica cómo se pasa el valor, y lo que sigue es el valor de la clave.

Tanto ese nombre como esa forma de escribirlo los decide el proveedor.

Con la clave que le llega, el servicio de pagos determina tres cosas: el dueño, las operaciones permitidas y el número de llamadas.

Lo que hizo my-appCabecera AuthorizationLo que hace el servicio de pagosLo que devuelve
Obtener la lista de pagosBearer sk_live_a1b2Determina el dueño y comprueba el alcance200 y JSON
Obtener la lista de pagosSe olvidó de añadirlaNo puede determinar el dueñoDevuelve 401
Crear un pagoBearer sk_read_9f3cSolo permite leerDevuelve 403
Llamar muchas veces en poco tiempoBearer sk_live_a1b2Cuenta las llamadas de cada dueñoDevuelve 429

Con un 401, comprueba el valor de la clave y el nombre de la cabecera; con un 403, qué operaciones están permitidas.

El límite de la cuarta fila es el límite de tasa (rate limit: el número máximo de llamadas que se aceptan en un periodo dado), y superarlo devuelve 429.

La clave indica de quién es la llamada

La clave de API es una cadena cuyo único trabajo es decir de quién es esta llamada.

El servicio de pagos mira la clave para comprobar el dueño y las operaciones permitidas y cuenta las llamadas de esa persona, así que sin clave devuelve 401, con una operación no permitida 403 y con demasiadas llamadas 429.

No pongas la clave en código que llega al navegador: guárdala solo dentro de tu propio servidor

Cualquiera que tenga la clave puede llamar como si fuera su dueño.

No hay ninguna pantalla que compruebe si es la persona real.

Adónde llegan los archivos de my-app
my-app al completo
Dentro de tu propio servidor (no llega al dispositivo)
.env
  • PAY_API_KEY=sk_live_a1b2
  • Se guarda en un archivo aparte del código
server.js
  • Añade a la llamada la clave leída de .env
  • El archivo en sí no se envía al dispositivo
Lo que llega al navegador (cualquiera puede leerlo)
  • index.html y script.js
  • No llama directamente al servicio de pagos: se lo pide a tu propio servidor
  • Solo guarda claves emitidas para usarse desde el navegador
Los archivos del marco superior no salen de tu propio servidor. Los del marco inferior se envían tal cual al dispositivo del usuario.

Aun siendo la misma clave, dónde la escribes cambia quién puede leerla.

Dónde está escrita la clave¿Llega al dispositivo?Quién puede leerlaQué pasa
.env (dentro del servidor)No llegaSolo quien accede al servidorFunciona según lo contratado
script.jsLlegaTodos los que abren la páginaOtros pueden llamar como tú
Un server.js publicadoNo llega, pero queda públicoTodos los que ven el códigoNo se puede borrar del historial de Git

Cuantas más personas pueden leer la clave en una fila, más cerca está esa fila de que otros llamen en tu nombre.

La tercera fila no llega al navegador, pero una vez registrada en Git se puede leer en el historial de cambios aunque la borres después.

Cuando las instrucciones dicen «ponla en .env», te están diciendo que uses la colocación de la primera fila.

Con una clave que ha salido fuera se pueden hacer dos cosas, y no tienen el mismo efecto.

Qué puedes hacer con una clave que ha salido fuera
sk_live_a1b2salió fueraBorrar esa líneadel códigoRevocarla enel panelEl valor leídosigue sirviendoSe rechazan lasllamadas con ella
La de la izquierda solo borra los caracteres que escribiste. La de la derecha deja la clave inservible en el lado del servicio de pagos. Solo con la de la derecha se rechazan las llamadas.

El valor que alguien leyó sigue siendo válido, y además queda en el historial de cambios de Git.

La de la derecha es la revocación (revoke: dejar en el proveedor una clave ya emitida en estado inservible).

Guarda la clave solo donde no llegue a ningún dispositivo

Cualquiera que tenga la clave puede usarla como su dueño.

Por eso no la escribas ni en archivos que llegan al dispositivo del usuario ni en código que publicas, y cuando se te escape fuera, revócala y emite una clave nueva en lugar de borrar los caracteres que escribiste.

El webhook es el mecanismo por el que el servicio externo llama a tu propio servidor

Que un pago se complete o que haya un reembolso son sucesos cuyo momento quien llama no puede saber.

Preguntar una y otra vez aumenta las llamadas inútiles y retrasa el momento en que te enteras.

El webhook (webhook: el mecanismo por el que, cuando ocurre un suceso determinado, el servicio externo envía una solicitud a una URL registrada) invierte esa dirección.

En tres formas de hacerlo, cuál de los dos lados envía la solicitud
=FormaQuién envíaQué se preparade antemanoLlamar a la APImy-app →servicio de pagosEndpoint yclave de APIPreguntar si yaterminómy-app →servicio de pagosCada cuánto preguntarWebhookServicio de pagos →my-appURL de my-app querecibe los avisos
Las dos filas de arriba tienen la misma dirección, por eso están unidas con una línea doble. Solo el webhook va del servicio de pagos a my-app.

Solo el webhook de la tercera fila va del servicio de pagos a my-app.

Lo único que preparas es registrar de antemano una URL que reciba los avisos.

Los avisos que llegan de un solo pago
Un usuario pagauna vezEl pago se completóSe creó el reciboHubo un reembolsomy-app/webhooks/payment
Incluso con un solo pago, llega un aviso distinto por cada suceso. Todos llegan a la única URL que registraste.

Llega un aviso distinto cuando el pago se completa, cuando se crea el recibo y cuando hay un reembolso.

De qué suceso es cada aviso está escrito en el cuerpo de la solicitud.

La flecha 1 es la dirección en la que llamas tú, y la flecha 2 la dirección en la que te llama el servicio externo.

La clave solo llega al servicio de pagos y nunca al dispositivo del usuario.

El webhook es una llamada en sentido contrario

El webhook es la llamada en la que el servicio de pagos llama a my-app.

Sirve para que te avisen en cuanto ocurre un suceso cuyo momento no puedes prever, y lo único que preparas es crear y registrar de antemano una URL que reciba los avisos.

Cualquiera puede llamar a la URL que recibe los avisos, así que comprueba la firma antes de procesar

La URL que recibe los avisos es pública, así que alguien que no sea el servicio de pagos también puede enviar a esa misma URL.

Lo que lo evita es la firma (signature: un valor calculado a partir de una cadena que solo conocen quien envía y quien recibe, que se añade a la solicitud y que quien recibe comprueba haciendo el mismo cálculo).

Un aviso que llegó del servicio de pagos
Una solicitud que recibió my-app
Línea 1 — método y URL
  • POST https://my-app.example.com/webhooks/payment
  • La URL que preparaste y registraste
Desde la línea 2 — cabeceras de la solicitud
  • La firma va aquí
  • El ID que distingue un aviso repetido suele ir aquí también
Tras una línea en blanco — el cuerpo
  • De qué suceso se trata, escrito en JSON
  • El ID del pago y su estado también van aquí
El marco exterior es una solicitud recibida. La firma va en la cabecera, y en el cuerpo está escrito de qué suceso se trata.

Comprueba la firma de la cabecera antes de leer el contenido.

Cuando no devuelves un éxito, quien envía manda otra vez el mismo aviso: eso es el reenvío (retry).

Registra el ID de cada aviso y salta los que ya procesaste.

La cadena que se usa para la comprobación, igual que la clave de API, no se escribe en el código, y cómo se añade lo compruebas en la documentación de la API.

Cuando un manual dice «verifica la firma», se refiere a esta comprobación.

Comprueba antes de leer y prepárate para una segunda entrega

La URL que recibe los avisos es pública, así que el hecho de que llegue una solicitud no te dice nada de quién la envía.

Comprueba la firma antes de leer el cuerpo y, si coincide, actualiza el registro y devuelve un código de estado de éxito; luego guarda los ID de los avisos que procesaste para saltar una segunda entrega.

QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1Cuando envías una solicitud con una clave de API añadida, ¿qué puede determinar el servicio externo?

Pregunta 2¿Qué problema hay en escribir una clave de API en código que llega al navegador?

Pregunta 3Cuando llega un aviso por webhook, ¿qué haces antes de leer su contenido?