API de gestión de Monosign, SCIM 2.0 y webhooks

Qué ha cambiado

Cada actualización del contenido se versiona. Seleccione una versión para compararla con la anterior.

Versión 7 → 8

Actualización

Se añadieron dos módulos para que el curso cubra el examen MCIE: clientes OAuth y duración de los tokens, lectura de un 403, tenants, los endpoints de asignaciones y derechos, las llamadas que hace el envío SCIM y cómo leer sus resultados, y Provision Services con sus dead letters. Se añadieron diagramas y listas de primera comprobación a las lecciones nuevas.

5 lecciones actualizadasduración

Actualización de contenido. Se notificó a los estudiantes inscritos.

La duración cambió de 30 a 34 minutos.

Un backend no habla con Monosign solo mediante una clave `Rest API`. Cuando su propia API debe aceptar tokens emitidos por Monosign, quien llama es un **cliente OAuth**, y unas pocas reglas deciden si su petición de token funciona. ### Una clave es un cliente Un cliente es una clave de aplicación de tipo `OIDC/OpenID`, `OAuth 2.0` o `JWT`. La clave es el `client_id` y el secreto de la clave es el `client_secret`. Los tres tipos de clave se sirven bajo tres prefijos de ruta: `/openid`, `/oauth` y `/jwt`. El controlador que hay detrás es el mismo, pero el prefijo decide qué tipo de clave se busca, de modo que el cliente debe llamar al prefijo del tipo con el que se creó. Un ID y un secreto correctos enviados al prefijo equivocado se rechazan. ### La petición de client credentials Un trabajo de backend no tiene usuario ni navegador, así que usa el flujo client credentials. La petición solo necesita el tipo de concesión y las credenciales propias del cliente: ``` POST /oauth/token Content-Type: application/x-www-form-urlencoded grant_type=client_credentials&client_id=<clave>&client_secret=<secreto de la clave> ``` En este flujo no hay dirección de redirección ni nombre de usuario, porque nadie inicia sesión. ::diagram api-client-credentials ### Los clientes públicos no pueden hacerlo Una clave con `Public Client` activado está pensada para aplicaciones de una sola página, móviles y de línea de comandos. No tiene secreto, PKCE pasa a ser obligatorio y el flujo client credentials se rechaza con `The client_credentials grant is not allowed for public clients.` No desactive la opción para que funcione un trabajo de backend. Registre un segundo cliente confidencial para ese trabajo, con su propia clave y secreto, para que cada llamante se pueda rotar por separado. ### Las duraciones van en minutos | Ajuste | Vacío o `0` significa | Unidad | | --- | --- | --- | | `Access Token Lifetime` | 5 minutos | minutos | | `Refresh Token Lifetime` | 30 minutos | minutos | | `ID Token Lifetime` | 1 minuto | minutos | Hasta v2026.07-hf02 la ruta de client credentials leía estos valores como segundos, aunque el formulario decía `In minutes`. Desde v2026.09 todas las rutas leen minutos. Una clave ajustada en la versión antigua con `3600` para una hora emite ahora tokens que viven 3600 minutos, es decir, 60 horas. Tras la actualización, introduzca `60`. ### Qué va en cada token `Audience` y `Resource` de la clave se escriben solo en el **token de acceso**. El token de ID va dirigido al propio cliente, por lo que su `aud` sigue siendo el ID del cliente. Una API que valide `aud` debe validar por tanto tokens de acceso, nunca tokens de ID. ### Deshabilitar un usuario no retira los tokens Los tokens de acceso ya emitidos siguen siendo válidos hasta su `exp`. Lo que se detiene es la siguiente renovación: para un usuario que no está activo o no está `Enabled`, el endpoint de token responde `The refresh token is no longer valid.` El intervalo entre ambos es la vida del token de acceso, así que un `Access Token Lifetime` corto es el control que lo reduce. ### Qué comprobar primero cuando falla una solicitud de token 1. ¿Coincide el prefijo de la ruta (`/openid`, `/oauth` o `/jwt`) con el tipo con el que se creó la clave? 2. ¿Está activado `Public Client`? Una clave así no puede usar el grant client credentials. 3. ¿Viven los tokens mucho más de lo previsto tras una actualización? Lea los campos de duración como minutos.
La mayoría de los casos de soporte de una integración empiezan con una sola llamada rechazada. La propia respuesta le dice qué hacer, si la lee entera. ### El 403 nombra el permiso Con API Security activado, una llamada a un endpoint cuyo permiso no está concedido a la clave responde HTTP 403. El cuerpo tiene este aspecto: ``` { "Message": "Permission Denied", "InternalMessage": "Permission denied for this API endpoint. You need to have one of the following permission(s): System.API.Users.View." } ``` `InternalMessage` enumera los permisos que acepta el endpoint. El método de trabajo es siempre el mismo: 1. Copie el nombre del permiso del 403. 2. Abra la aplicación, `Keys`, la clave y la pestaña `Permissions`. 3. Busque ese nombre con `Search` y concédalo con `Grant`. Conceda exactamente lo que nombró el 403. Un permiso más amplio aumenta lo que la clave puede llamar. ### Por qué la siguiente llamada aún puede fallar Cada proceso de la API responde desde su propia copia en memoria de los ajustes de seguridad. Un cambio se aplica cuando el proceso descarta su entrada en caché, lo que ocurre poco después, no al instante. Detrás de un balanceador de carga, dos instancias pueden discrepar durante ese breve intervalo. Si una llamada sigue devolviendo 403 justo después de conceder el permiso, espere un momento y pruebe una instancia cada vez. No reaccione concediendo más permisos ni desactivando API Security. ::diagram api-403-path ### Lo que el valor por defecto de v2026.09 no toca El valor seguro por defecto se escribe en un único momento: cuando se crea una nueva clave `Rest API` en una aplicación que nunca tuvo un ajuste. Dos consecuencias ayudan cuando un cliente pregunta por sus integraciones existentes: - Una aplicación con una elección explícita, activada o desactivada, la conserva. - Editar una clave existente nunca aplica el valor por defecto. ### Tenants Una clave pertenece a un tenant. La clave de un tenant de cliente nunca puede actuar en otro tenant. Desde v2026.10 existe un único traspaso admitido: una clave de la **aplicación maestra `api` del tenant principal** puede enviar con su llamada una cabecera de traspaso del tenant base, y la llamada se ejecuta entonces dentro del tenant de la petición. Cualquier otra clave que lo intente recibe `Invalid Application Key`. Para una automatización que atiende a varios tenants, la elección es por tanto sencilla: use la clave propia de cada tenant de destino o use la aplicación maestra del tenant principal. ### Las escrituras por API no aprovisionan por sí solas Crear, guardar o eliminar un usuario en Management siempre pone al usuario en la cola de los Provision Services. La API se comporta de otro modo: una creación o actualización de usuario solo encola el aprovisionamiento cuando la llamada establece `AutoProvision`. Si los usuarios creados por una integración de RR. HH. nunca llegan al endpoint de aprovisionamiento de un cliente y los creados a mano sí, revise el cuerpo de la petición antes de revisar el servicio.
Tres familias de recursos sostienen la mayor parte de la automatización del ciclo de vida: las asignaciones de aplicaciones, los derechos (entitlements) y las auditorías. Cada una tiene un comportamiento que sorprende a los integradores. ### Asignaciones de aplicaciones | Llamada | Permiso | Qué hace | | --- | --- | --- | | `POST v1.4/application-users/detail` | `System.API.ApplicationUsers.View` | Lee una asignación | | `PUT v1.4/application-users` | `System.API.ApplicationUsers.Edit` | Cambia una asignación existente | | `DELETE v1.4/application-users/{id}` | `System.API.ApplicationUsers.Remove` | Elimina una asignación (v2026.10 y posteriores) | `PUT` nunca crea una asignación. Busca una asignación activa y no eliminada del `UserId` y el `ApplicationId` que envía, y responde 404 `Application user not found` cuando no existe. ### Ampliar una caducidad de la forma correcta La petición tiene dos campos de fecha con funciones distintas. `NewExpirationDate` **escribe** la nueva caducidad. El antiguo `ExpirationDate` solo **acota la búsqueda**, de modo que enviar ahí la fecha nueva hace que la búsqueda no encuentre la fila y la llamada responda 404. ``` PUT v1.4/application-users { "UserId": "<id de usuario>", "ApplicationId": "<id de aplicación>", "NewExpirationDate": "2026-12-31T23:59:59Z" } ``` No envíe `ExpirationDate`. Compruebe también qué envía su biblioteca JSON para una fecha sin valor. `NewExpirationDate` se aplica siempre que tiene un valor, y el servidor no protege frente a valores pasados: una fecha por defecto como `0001-01-01T00:00:00` hace caducar la asignación al instante. Envíe `null` u omita el campo cuando no quiera cambiar la caducidad. ### Qué cambió en v2026.10 - Una clave sin derechos maestros solo alcanza las asignaciones de **su propia aplicación**. Detail, `PUT` y `DELETE` sobre la asignación de otra aplicación responden 404 `Application user not found`. Una integración que gestiona varias aplicaciones necesita derechos maestros o una clave por aplicación. - Existe `DELETE v1.4/application-users/{id}`. Elimina la asignación de forma lógica, ejecuta el disparador `Removed` y escribe el evento de revocación en la línea de tiempo de accesos. Úselo para el desaprovisionamiento. Fijar una caducidad pasada solo hace caducar la asignación y no deja ese rastro. ### Pertenencias a grupos mediante entitlements `POST v1.5/entitlements/groups` añade un usuario a un grupo. Desde v2026.10, repetir la misma alta responde `409` con el código `EntitlementAlreadyExists` e incluye el ID de la pertenencia existente. Para un cliente que reintenta tras un tiempo de espera agotado, esta es la respuesta que hace idempotente la llamada: cuéntela como hecha. `DELETE v1.5/entitlements/{objectAssignmentId}` con ese ID termina la pertenencia. Antes de v2026.10 la misma llamada guardaba un registro que el almacén de grupos nunca veía, por lo que las reglas y los disparadores ignoraban la pertenencia. Esos registros antiguos siguen ignorados después de la actualización. La solución es volver a añadir las pertenencias a través de la API. ::diagram api-entitlement-retry ### Las auditorías no son una API de listado `v1.4/audit` ofrece `GET {id}`, `POST` y `POST bulk`. Los dos últimos escriben filas de auditoría para sistemas externos. No existe ruta de listado, aunque hay un permiso llamado `System.API.Audits.List`, y la página Audit tampoco exporta a fichero. Para llevar una semana de filas de auditoría a un data lake, cree un informe de Report Studio sobre el origen de datos `Audit Events` y entréguelo como fichero.
Un fabricante de destino preguntará qué operaciones SCIM tiene que admitir. La respuesta es breve, y conocerla explica la mayoría de los síntomas que encontrará después. ### Las llamadas para un usuario Para cada usuario asignado, el envío primero busca al usuario y después decide: ``` GET /Users?filter=userName eq "jdoe" ``` | Resultado de la búsqueda | Asignación | Siguiente llamada | | --- | --- | --- | | Ningún usuario | Activa | `POST /Users` | | Un usuario | Activa | `PUT /Users/{id}` | | Un usuario | Inactiva | `DELETE /Users/{id}` | | Más de un usuario | Cualquiera | Ninguna, el usuario se aborta | El documento de usuario lleva `userName`, el correo de trabajo, nombre y apellidos, `externalId` y `active`. El envío de usuarios no utiliza `PATCH`. Por tanto, un destino debe admitir el parámetro `filter` con `eq`, además de `POST`, `PUT` y `DELETE` sobre `/Users`. ::diagram api-scim-user-decision ### Elegir el atributo de búsqueda `User Identifier Property`, en los ajustes avanzados, decide qué atributo usa el filtro. El valor por defecto es `externalId`. Los otros valores útiles son `userName` y `email`. Dos líneas del registro del servicio indican que la elección no encaja con el destino: | Línea del registro del servicio | Qué significa | Solución | | --- | --- | --- | | `SCIM API returned no result for user ... Will be created.` en cada ejecución, con duplicados que se acumulan | El destino no conserva el atributo por el que filtra, así que la búsqueda siempre falla | Elija un atributo que el destino conserve, como `userName` o `email` | | `SCIM API returned more than one user ...` y el usuario nunca se actualiza | El atributo no es único en el destino | Elija un atributo que apunte exactamente a una cuenta | ### Force Sync y la programación `Force Sync` envía usuarios y grupos de inmediato, sin tener en cuenta `Features` ni `Enable Auto-sync`, lo que lo convierte en el botón adecuado mientras prueba. Su respuesta es del tipo `120 users sync is completed. [112 success / 0 skipped / 8 error]`. Lea las cifras con cuidado: el contador skipped nunca se incrementa, así que los usuarios omitidos, por ejemplo por no tener nombre, aparecen en error. Revise el registro del servicio antes de culpar al destino. Un envío **programado** solo empieza cuando se cumplen tres cosas: la aplicación está habilitada, `Enable Auto-sync` está activado y una entrada de `Timing` tiene una siguiente ocurrencia ya vencida. `Timing` ofrece cada hora en un minuto dado o cada día a una hora dada, ambos en UTC, y el formulario muestra al lado la hora UTC y la hora local actuales. Un cliente en UTC+3 que quiere las 02:00 locales introduce `Every Day at 23:00`. ### Grupos Los grupos se escriben con `PUT` y se identifican por `externalId`, que contiene el ID del grupo de Monosign. El paso de grupos lee el `externalId` de cada grupo del destino como uno de esos ID. Un solo grupo antiguo del destino con una etiqueta de texto en `externalId` detiene todo el paso de grupos, y no llega ninguno de los grupos asignados. Limpie primero ese grupo en el destino. `Group Identifier Property` se guarda pero el envío no lo lee, así que cambiarlo no ayuda. ### Proxy de salida El envío lee el ajuste global `Proxy Host` en Settings, `System`. Su descripción dice que el proxy se usa en los servicios de SCIM, SMS, llamadas, push y licencias. Cuando el campo está vacío, el envío conecta directamente, lo que falla en redes donde solo el proxy puede salir a internet. ### Leer, en cambio, los grupos de una aplicación SaaS El origen `SCIM Entitlement Provider` funciona en sentido contrario: importa los grupos de la aplicación como derechos y sus miembros como concesiones. Su `Test` ejecuta cuatro pasos: `Connect to SCIM endpoint`, `Read users and groups`, `Provisioning capability` y `User matching`. Si el tercero termina con el aviso de que el servidor no anuncia compatibilidad con PATCH, la importación sigue funcionando, pero añadir y quitar miembros desde Monosign probablemente fallará, porque la pertenencia se aprovisiona con `PATCH /Groups/{id}`. ### Qué comprobar primero | Síntoma | Dónde mirar | | --- | --- | | Duplicados, o usuarios que nunca se actualizan | `User Identifier Property` y las dos líneas del registro del servicio de arriba | | `Force Sync` informa de errores | El registro del servicio, porque los usuarios omitidos cuentan como errores | | El envío programado nunca empieza | Aplicación habilitada, `Enable Auto-sync` activado y una entrada de `Timing` en UTC | | No llega ningún grupo asignado | El `externalId` de los grupos que ya existen en el destino | | El envío no puede conectar | `Proxy Host` en Settings, `System` |
SCIM no es la única vía de salida. Un **Provision Service** vincula un proveedor de aprovisionamiento a una aplicación, con un título, una `Url`, ajustes JSON y reglas. El servicio de aprovisionamiento de usuarios evalúa a cada usuario frente a cada servicio habilitado y envía el trabajo de aprovisionar o desaprovisionar al endpoint del cliente. Si usted construye ese endpoint, la vida de una fila de trabajo decide su diseño. ### La vida de una fila | Paso | Qué ocurre | | --- | --- | | En cola | Una fila espera como `WaitingForProvision` (o su equivalente de desaprovisionamiento) | | Enviada | El servicio hace POST a la `Url`; la fila pasa a `Provisioning` | | Su endpoint responde 2xx | No cambia nada más. No hay devolución de llamada y nada marca la fila como aprovisionada | | Aproximadamente una hora después | Un barrido devuelve a la espera las filas que siguen en curso, y la fila se envía de nuevo | | 48 horas después de crearse la fila | Se marca como error con el mensaje de que el presupuesto de reintentos está agotado y aparece en `Dead Letters` | La consecuencia es la frase más importante de esta lección: **un 2xx no cierra la fila, así que su endpoint recibe al mismo usuario otra vez aproximadamente cada hora.** Diséñelo para que una repetición no cambie nada: busque primero la cuenta, créela solo si falta y responda 2xx en ambos casos. ::diagram api-provision-row-life ### Tres ajustes que confunden - **`Url` no es obligatorio.** Con una `Url` vacía, las filas del servicio se quedan en `WaitingForProvision` para siempre y no se registra ningún error. Compruébelo primero cuando un servicio nuevo no entregue nada. - **`State` es una insignia almacenada.** No inicia ni detiene nada. - **`Remove` no borra.** Solo pone `Is Enabled` en false, y la mayoría de los roles reciben 403 al intentarlo. Para retirar un servicio durante un tiempo, use `Edit`, desmarque `Is Enabled` y guarde. La pausa es reversible y no desaprovisiona las cuentas que el servicio ya creó. ### Quién queda fuera del alcance Un usuario inactivo, no `Enabled` o **sin dirección de correo** se considera fuera de todas las reglas y se pone en cola para desaprovisionarlo. Una limpieza de datos que vacíe direcciones de correo puede, por tanto, eliminar cuentas reales en el lado del cliente. Acuérdelo con el equipo de RR. HH. antes de una limpieza así. `Start Full User Provision` comprueba a cada usuario frente a cada servicio habilitado. El aviso `Full User Provision is Started.` aparece antes de que se haga ningún trabajo, y no hay vista de progreso. Revise las reglas y `Is Enabled` en cada servicio antes de pulsarlo, porque los usuarios fuera de una regla se ponen en cola para su eliminación. ### Dead letters del aprovisionamiento Management, System, Services, `Dead Letters` enumera las filas de aprovisionamiento que agotaron su presupuesto. No se reintentan por sí solas. | Botón | Cuándo usarlo | Efecto | | --- | --- | --- | | `Requeue` | La causa está corregida y el usuario sigue necesitando la cuenta | La fila vuelve a su estado de espera y el servicio la recoge de nuevo. Puede fallar otra vez y volver a la lista | | `Discard` | El trabajo ya se hizo de otra forma, por ejemplo TI creó la cuenta a mano | La fila pasa a un estado final descartado, conserva su contenido y el último error, y no se envía nada | Un descarte no se puede deshacer, pero no bloquea el futuro: cuando el usuario vuelve a ser elegible, se pone en cola trabajo nuevo.