El problema que resuelven las solicitudes de origen relacionadas
Las llaves de acceso están vinculadas a un sitio web específico y solo se pueden usar para acceder al sitio web para el que se crearon.
Esto se especifica en el ID del grupo de confianza (ID del RP), que para las llaves de acceso creadas para el dominio example.com podría ser www.example.com
o example.com
.
Si bien los IDs de RP evitan que las llaves de acceso se usen como una sola credencial para la autenticación en todas partes, crean problemas en los siguientes casos:
- Sitios con varios dominios: Los usuarios no pueden usar la misma llave de acceso para acceder a diferentes dominios específicos de cada país (por ejemplo,
example.com
yexample.co.uk
) administrados por la misma empresa. - Dominios de marca: Los usuarios no pueden usar la misma credencial en diferentes dominios que usa una sola marca (por ejemplo,
acme.com
yacmerewards.com
). - Apps para dispositivos móviles: A menudo, las apps para dispositivos móviles no tienen su propio dominio, lo que dificulta la administración de credenciales.
Existen soluciones alternativas basadas en la federación de identidades y otras basadas en iframes, pero son incómodas en algunos casos. Las solicitudes de origen relacionadas ofrecen una solución.
Solución
Con las solicitudes de origen relacionadas, un sitio web puede especificar los orígenes que pueden usar su ID de RP.
Esto permite que los usuarios reutilicen la misma llave de acceso en varios sitios que administras.
Para usar las solicitudes de origen relacionadas, debes publicar un archivo JSON especial en una URL https://{RP ID}/.well-known/webauthn
específica. Si example.com
desea permitir que los orígenes adicionales lo usen como un ID de RP, debe entregar el siguiente archivo en https://example.com/.well-known/webauthn:
.
{
"origins": [
"https://example.co.uk",
"https://example.de",
"https://example-rewards.com"
]
}
La próxima vez que alguno de estos sitios realice una llamada para la creación de una llave de acceso (navigator.credentials.create
) o la autenticación (navigator.credentials.get
) que use example.com
como un ID de RP, el navegador notará un ID de RP que no coincide con el origen solicitante. Si el navegador admite solicitudes de origen relacionadas, primero busca un archivo webauthn
en https://{RP ID}/.well-known/webauthn
. Si el archivo existe, el navegador verifica si el origen que realiza la solicitud está en la lista de entidades permitidas en ese archivo. Si es así, se continúa con los pasos de creación de la llave de acceso o autenticación.
Si el navegador no admite solicitudes de origen relacionadas, muestra un SecurityError
.
Navegadores compatibles
- Chrome: Compatible a partir de Chrome 128.
- Safari: Compatible a partir de la versión beta 3 de macOS 15 y en iOS 18 beta 3 para dispositivos móviles.
- Firefox: Awaiting position.
Cómo configurar solicitudes de origen relacionadas
En la siguiente demostración, se usa el ejemplo de dos sitios: https://ror-1.glitch.me
y https://ror-2.glitch.me
.
Para permitir que los usuarios accedan con la misma llave de acceso en ambos sitios, usa solicitudes de origen relacionadas para permitir que ror-2.glitch.me
use ror-1.glitch.me
como su ID de RP.
Demostración
https://ror-2.glitch.me implementa solicitudes de origen relacionadas para usar ror-1.glitch.me como un ID de RP, por lo que ror-1
y ror-2
usan ror-1.glitch.me
como un ID de RP cuando crean una llave de acceso o se autentican con ella.
También implementamos una base de datos de llaves de acceso compartida en estos sitios.
Observa la siguiente experiencia del usuario:
- Puedes crear una llave de acceso y autenticarte con ella en
ror-2
, aunque su ID de RP searor-1
(y noror-2
). - Una vez que crees una llave de acceso en
ror-1
oror-2
, podrás autenticarte con ella en ambos.ror-1
ror-2
Debido a queror-2
especificaror-1
como un ID de RP, realizar una solicitud de creación o autenticación de llaves de acceso desde cualquiera de estos sitios es lo mismo que realizar la solicitud en ror-1. El ID del RP es lo único que vincula una solicitud a un origen. - Una vez que crees una llave de acceso en
ror-1
oror-2
, Chrome podrá autocompletarla en ambos.ror-1
ror-2
- Una credencial creada en cualquiera de estos sitios tendrá un ID de RP de
ror-1
.
Ver código:
- Consulta el archivo
./well-known/webauthn
configurado en la base de código de ror-1. - Consulta las ocurrencias de
RP_ID_ROR
en la base de código de ror-2.
Paso 1: Implementa una base de datos de cuentas compartida
Si deseas que los usuarios puedan acceder con la misma llave de acceso en site-1
y site-2
, implementa una base de datos de cuentas que se comparta en estos dos sitios.
Paso 2: Configura tu archivo JSON .well-known/webauthn en site-1
Primero, configura site-1.com
de modo que permita que site-2.com
lo use como un ID de RP. Para ello, crea tu archivo JSON de webauthn:
{
"origins": [
"https://site-2.com"
]
}
El objeto JSON debe contener orígenes con nombres de clave cuyo valor sea un array de una o más cadenas que contengan orígenes web.
Limitación importante: Máximo 5 etiquetas
Cada elemento de esta lista se procesará para extraer el TLD electrónico + 1 etiqueta.
Por ejemplo, las etiquetas de eTLD + 1 de example.co.uk
y example.de
son example
. Sin embargo, la etiqueta de eTLD+1 de example-rewards.com
es example-rewards
.
En Chrome, la cantidad máxima de etiquetas es 5.
Paso 3: Publica tu JSON de .well-known/webauthn en el sitio 1
Luego, entrega tu archivo JSON en site-1.com/.well-known/webauthn
.
Por ejemplo, en Express:
app.get("/.well-known/webauthn", (req, res) => {
const origins = {
origins: ["https://site-2.com"],
};
return res.json(origins);
});
Aquí, usamos res.json
exprés, que ya establece el content-type
correcto ('application/json'
).
Paso 4: Especifica el ID de RP deseado en el sitio 2
En tu base de código de site-2
, establece site-1.com
como el ID de RP en todas partes donde sea necesario:
- Cuando se crea la credencial:
- Establece
site-1.com
como el ID de RP en eloptions
de creación de credenciales que se pasa a la llamada de frontendnavigator.credentials.create
y, por lo general, se genera del servidor. - Establece
site-1.com
como el ID de RP esperado, ya que ejecutas verificaciones de credenciales antes de guardarlas en tu base de datos.
- Establece
- Después de la autenticación:
- Establece
site-1.com
como el ID de RP en eloptions
de autenticación que se pasa a la llamada del frontendnavigator.credentials.get
y que, por lo general, se genera del servidor. - Establece
site-1.com
como el ID de RP esperado que se verificará en el servidor, a medida que ejecutas verificaciones de credenciales antes de autenticar al usuario.
- Establece
Solución de problemas
Otras consideraciones
Cómo compartir llaves de acceso en sitios y apps para dispositivos móviles
Las solicitudes de origen relacionadas permiten que los usuarios reutilicen una llave de acceso en varios sitios. Para permitir que los usuarios reutilicen una llave de acceso en un sitio web y una app para dispositivos móviles, usa las siguientes técnicas:
- En Chrome: Vínculos de recursos digitales. Obtén más información en Agregar compatibilidad con Vínculos de recursos digitales.
- En Safari, ve a Dominios asociados.
Cómo compartir contraseñas entre sitios
Las solicitudes de origen relacionadas permiten que los usuarios reutilicen una llave de acceso en todos los sitios. Las soluciones para compartir contraseñas entre sitios varían según el administrador de contraseñas. Para el Administrador de contraseñas de Google, usa Vínculos de recursos digitales . Safari tiene un sistema diferente.
Rol de los administradores de credenciales y los agentes de usuario
Esto va más allá de tu alcance como desarrollador de sitios, pero ten en cuenta que, a largo plazo, el ID de RP no debe ser un concepto visible para el usuario en el usuario-agente o el administrador de credenciales que usan tus usuarios. En cambio, los agentes de usuario y los administradores de credenciales deben mostrar a los usuarios dónde se usaron sus credenciales. Este cambio llevará tiempo implementarse. Una solución temporal sería mostrar el sitio web actual y el sitio de registro original.