CORS y orígenes permitidos
Una clave publicable puede tener una lista de orígenes permitidos: los sitios web que pueden utilizarla. Esta página explica dónde se comprueba esa lista, qué muestra el navegador cuando falla una comprobación y qué cosas no protege la lista.
Un origen se compone del esquema, el host y el puerto de una página, por ejemplo https://www.example.com o http://localhost:3000. No incluye ninguna ruta.
La lista es opcional
Una clave publicable funciona con una lista vacía. Una lista vacía significa que cualquier origen puede usar la clave. Así se crea una clave cuando no se indican orígenes y también es posible vaciar la lista más adelante.
Añade orígenes antes de implementar una clave en un sitio de producción. Con una lista configurada, una copia de tu clave pegada en la página web de otra persona deja de funcionar allí. Más abajo se explica qué protege esta medida y cuáles son sus límites.
Las claves de servidor ignoran la lista. Una clave de servidor nunca puede utilizarse desde un navegador, independientemente de lo que indique su lista.
Cómo escribir una entrada
| Regla | Ejemplo |
|---|---|
| Solo el esquema, el host y, opcionalmente, el puerto. Sin ruta, consulta ni barra final. | https://www.example.com, no https://www.example.com/ |
Se requiere https. Solo se acepta http para localhost, 127.0.0.1 y [::1]. La página de claves API no admite [::1]; configúralo mediante la API de gestión de claves. | http://localhost:3000 |
La coincidencia es exacta. No hay comodines y cada subdominio es un origen diferente. Una entrada con * se guarda tal cual y no coincide con ningún sitio. | https://example.com y https://www.example.com son dos entradas |
El puerto forma parte del origen. Omite los puertos predeterminados (443 para https, 80 para http). | https://example.com, no https://example.com:443 |
| Se admiten hasta 100 entradas por clave. Se rechazan los duplicados. |
Las entradas se almacenan en minúsculas y sin los puertos predeterminados para que coincidan con lo que envía el navegador.
Una página abierta desde el disco (file://) no tiene un origen que puedas añadir. Durante el desarrollo, sirve la página desde http://localhost.
Configura la lista en la página de claves API de kaleidr.com/api-keys o mediante allowed_origins en la API de gestión de claves.
Dónde se comprueba la lista
| Paso | Comprobación | Si falla |
|---|---|---|
| 1. Intercambio de sesión | La cabecera Origin de la solicitud debe figurar en la lista de la clave, si se ha definido una. | 403 origin_not_allowed. No se emite ninguna sesión. Si falta por completo la cabecera Origin, se devuelve 403 origin_required. |
| 2. Todas las llamadas en ejecución | Un token de sesión solo funciona desde el origen para el que se emitió. | 403 session_origin_mismatch. |
| 3. Todas las llamadas en ejecución | El origen de la sesión debe seguir figurando en la lista de la clave. | 401. Al eliminar un origen de una clave se invalidan las sesiones ya emitidas para él. |
| 4. Solicitudes de mapa base que incluyen una clave | El Editor integrado envía tu clave publicable a https://tile.kaleidr.com al solicitar estilos, sprites y fuentes. El sitio de la página debe estar en la lista de la clave para que se reconozca. | La solicitud se trata como si no tuviera clave y puede rechazarse con 429 tile_access_restricted. |
| 5. La respuesta | La API solo añade Access-Control-Allow-Origin cuando la credencial es válida y el origen está permitido. | El navegador impide que la página lea la respuesta. |
El paso 5 es el funcionamiento habitual de CORS y explica el aspecto que tienen estos fallos en un navegador.
Solicitud de comprobación previa
Antes de un POST entre sitios con un cuerpo JSON, el navegador envía una solicitud de comprobación previa OPTIONS. Kaleidr responde a todas con 204 y refleja el origen que realizó la solicitud, porque dicha comprobación no incluye credenciales y no puede contrastarse con una clave. La lista se aplica a la solicitud real.
| Cabecera de respuesta de comprobación previa | Valor |
|---|---|
Access-Control-Allow-Methods | GET, POST, OPTIONS |
Access-Control-Allow-Headers | Authorization, Content-Type, Accept, X-Api-Key, X-Request-Id |
Access-Control-Max-Age | 600 |
Una solicitud que envíe cualquier otra cabecera falla en la comprobación previa del navegador. No añadas cabeceras personalizadas a las llamadas realizadas desde una página.
En una respuesta permitida, la API también envía Access-Control-Expose-Headers: Retry-After, X-Request-Id, para que el código de la página pueda leer ambas cabeceras. Nunca envía Access-Control-Allow-Credentials: la API no usa cookies.
Qué se ve cuando se rechaza un origen
Cuando se rechaza el origen o la credencial, la respuesta no contiene la cabecera Access-Control-Allow-Origin. Por eso, el navegador oculta la respuesta al código de la página. La página no ve el cuerpo de la respuesta 401 o 403, sino un error de red.
En la consola:
Access to fetch at 'https://api.kaleidr.com/inference-api/b2b/v1/sdk/sessions' from origin
'https://www.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
seguido de un error del SDK que contiene [kaleidr:chat] (o el producto que hayas montado). No se muestra nada.
Para identificar la causa real, abre la pestaña Red del navegador, selecciona la solicitud sessions y consulta su estado y respuesta:
| Estado y código en la pestaña Red | Causa | Solución |
|---|---|---|
403 origin_not_allowed | El origen de esta página no figura en la lista de la clave. | Añade exactamente el origen mostrado en la cabecera Origin de la solicitud. |
401 Invalid or missing API key | La clave está mal escrita, revocada o caducada. | Comprueba la clave en la página de claves API. |
403 server_key_in_browser | Se ha enviado una clave de servidor desde una página. | Usa una clave publicable en la página. Rota la clave de servidor. |
403 session_origin_mismatch | Se utilizó un token de sesión desde un origen diferente al que lo solicitó. | Intercambia la sesión desde la página que la utiliza. |
La comprobación previa falla y no aparece ningún POST | La solicitud envió una cabecera fuera de la lista permitida. | Elimina la cabecera personalizada. |
Una vez aceptados la credencial y el origen, los errores posteriores pueden ser leídos por la página y no generan un error CORS. Si una clave es válida para ese origen pero no tiene permiso para el producto, el intercambio falla con un 403 legible (product_not_allowed, insufficient_scope o tier_capability_not_allowed) y el SDK registra kaleidr session exchange failed (403). Si una sesión válida recibe un 429, llega con el cuerpo de la respuesta y la cabecera Retry-After. Los códigos se explican en Autenticación y ámbitos.
Una misma solicitud nunca muestra un error CORS desde una terminal porque CORS es una regla del navegador. Por tanto, curl permite comprobar rápidamente una pareja de clave y origen:
curl -i https://api.kaleidr.com/inference-api/b2b/v1/sdk/sessions \
-H "X-Api-Key: kld_pk_live_…" \
-H "Origin: https://www.example.com" \
-H "Content-Type: application/json" \
-d '{"product":"chat"}'
Un origen permitido devuelve 200 con access-control-allow-origin: https://www.example.com. Uno rechazado devuelve 403 {"detail":"origin_not_allowed"} sin esa cabecera.
Por qué se rechazan las claves de servidor en un navegador
Una clave de servidor es un secreto permanente. Cualquiera que la obtenga puede llamar a la API en nombre de tu organización hasta que la revoques. El código fuente de una página es público, de modo que poner una clave de servidor en una página supone divulgarla.
Kaleidr la rechaza en tres puntos:
- El SDK rechaza una clave
kld_sk_…al montarse, muestra un error de consola y no realiza ninguna solicitud de red. - La API responde con 403
server_key_in_browsera cualquier solicitud con clave de servidor que incluya una cabeceraOrigin. - La respuesta no incluye cabeceras CORS, por lo que el código de la página no podría leerla en ningún caso.
Ninguna de estas medidas revierte la filtración. CORS bloquea la respuesta, no la solicitud: cuando la API la rechaza, la clave ya se ha enviado y cualquiera que inspeccione la página puede verla. Si una clave de servidor ha estado incluida en una página, rótala.
La lista no mantiene las claves en secreto
Los navegadores establecen correctamente la cabecera Origin, pero otros clientes no están obligados a hacerlo. Un script, una herramienta de línea de comandos o un servidor puede enviar el Origin que quiera, como muestra el ejemplo anterior con curl. Por tanto:
- La lista impide que otros sitios web usen tu clave desde los navegadores de sus visitantes. Ese es su propósito y lo cumple bien.
- La lista no detiene a quien está decidido a usarla si copia tu clave publicable y envía solicitudes con tu origen desde fuera de un navegador.
Planifica teniendo esto en cuenta. Trata todo lo que pueda consultar una clave publicable como accesible para cualquiera que pueda leer tu página:
- Limita el consumo posible con un tope mensual por clave y su límite de solicitudes. Consulta Cuotas y límites de solicitudes.
- No incluyas el ámbito
vendoren una clave publicable salvo que los datos a los que da acceso sean datos que publicarías en esa página. Consulta Autenticación y ámbitos. - Usa una clave por sitio web, para poder revocar una sin afectar a las demás.
El modelo de seguridad ofrece una visión más completa.
Credenciales en las URL
Las llamadas a la API de la plataforma envían la credencial en una cabecera, nunca en una URL. Las solicitudes de mapas base realizadas por las integraciones de Kaleidr son la única excepción: incluyen una credencial de navegador en la URL de solicitud, donde puede aparecer en el historial del navegador y en los registros de red. Esto es aceptable para una credencial publicable, que ya es pública, pero nunca para una clave de servidor. No incluyas kld_sk_… en ninguna URL.
Modificar la lista
- Añadir un origen surte efecto en el siguiente intercambio de sesión desde ese origen. Las solicitudes de mapas base pueden tardar unos minutos en reconocer el cambio.
- Eliminar un origen rechaza nuevos intercambios desde él e invalida las sesiones existentes en su siguiente solicitud.
- Vaciar la lista permite de nuevo «cualquier origen».
Temas relacionados
- Autenticación y ámbitos: el intercambio de sesión y todos los códigos 401 y 403.
- Modelo de seguridad: qué permite hacer cada credencial si se divulga.
- Política de seguridad de contenidos: los hosts que debe permitir tu página.
- Solución de problemas: problemas clasificados por síntoma.