> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.rhombus.community/llms.txt
> Use this file to discover all available pages before exploring further.

# Aprovisionamiento SAML SSO y SCIM

> Configura el inicio de sesión único SAML y el aprovisionamiento de usuarios SCIM para Rhombus mediante la API: integra Okta, Azure AD, Google Workspace, OneLogin y otros IdP.

<Note>
  Esta página fue traducida automáticamente. Si encuentra errores o tiene sugerencias, [contáctenos](mailto:support@rhombus.com).
</Note>

## Descripción general

Rhombus soporta **SAML 2.0** para que tus empleados puedan iniciar sesión en la Consola de Rhombus con su identidad corporativa existente (Okta, Azure AD / Microsoft Entra, Google Workspace, OneLogin y cualquier IdP compatible con SAML), y **SCIM 2.0** para que los cambios en el ciclo de vida de los usuarios en tu IdP se propaguen automáticamente a Rhombus.

Esta guía cubre la superficie de la **API** para configurar ambos. Úsala cuando necesites:

* **Gestionar Rhombus como infraestructura como código** (Terraform, Pulumi, scripts de CI internos)
* **Rotar los certificados de firma del IdP** con una cadencia programada
* **Incorporar muchas organizaciones de Rhombus** desde el plano de control de un partner o MSP
* **Auditar o comparar** la configuración de identidad entre entornos
* **Poner en marcha un nuevo tenant** de principio a fin sin hacer clic en la Consola

Si solo necesitas configurar SSO una vez para una sola organización, la [Consola de Rhombus](https://console.rhombussystems.com/) tiene una interfaz para todo lo que aparece en esta guía, pero todo lo que la interfaz puede hacer está expuesto a través de la API.

<Note>
  **Lo que esta guía no es.** Si eres un desarrollador externo que crea una aplicación que autentica a usuarios de Rhombus (un flujo de "Iniciar sesión con Rhombus"), lo que buscas es [Iniciar sesión con Rhombus](/es/oauth-authentication). Eso es OAuth 2.0 con Rhombus como proveedor de identidad: una superficie completamente distinta de la configuración de SSO para empleados que se cubre aquí.
</Note>

## Arquitectura de un vistazo

Dos flujos independientes comparten tu IdP, pero por lo demás no dependen el uno del otro:

```mermaid theme={null}
flowchart LR
    subgraph IdP["Your IdP (Okta, Azure AD, Google, etc.)"]
        Users[Users & Groups]
        Meta[SAML Metadata XML]
    end

    subgraph Rhombus["Rhombus"]
        Console[Rhombus Console<br/>Sign-in page]
        API[api2.rhombussystems.com]
        SCIM[SCIM endpoint<br/>scimEndpointUrl from getScimDisplayInfo]
    end

    Users -- "SAML assertion on login" --> Console
    Meta -. "uploaded via updateSAMLSettingsV2" .-> API
    Users -- "SCIM create/update/delete" --> SCIM
    API -- "exposes scimEndpointUrl" --> IdP
```

* **SAML SSO** autentica a los usuarios en el momento del inicio de sesión. Tu IdP envía una aserción SAML a Rhombus; Rhombus la valida contra el XML de metadatos del IdP que subiste.
* **SCIM** propaga los eventos del ciclo de vida de los usuarios (creación, actualización, desactivación) desde tu IdP a Rhombus de forma continua, sin requerir que los usuarios inicien sesión primero.

Puedes ejecutar cualquiera de los dos por sí solo, pero la mayoría de las implementaciones ejecutan ambos: **SAML para el inicio de sesión, SCIM para el aprovisionamiento**.

## Antes de comenzar

<Info>
  Antes de comenzar, asegúrate de tener:

  * Una **API key de Rhombus** con permisos de administrador de organización (generada en la [Consola de Rhombus](https://console.rhombussystems.com/) en **Settings → API Management**)
  * Un **proveedor de identidad** que soporte SAML 2.0 y (para el aprovisionamiento) SCIM 2.0
  * El **XML de metadatos del IdP** de tu aplicación SAML, ya sea como archivo o como URL
  * Una cuenta de usuario de recuperación con una contraseña que **omita SAML**; consulta [acceso break-glass](#acceso-break-glass) antes de habilitar SSO
</Info>

***

# Parte 1: SAML SSO

Dos endpoints cubren todo el ciclo de vida de la configuración SAML:

| Endpoint                             | Propósito                                            |
| ------------------------------------ | ---------------------------------------------------- |
| `POST /api/org/getSAMLSettingsV2`    | Leer la configuración SAML actual de la organización |
| `POST /api/org/updateSAMLSettingsV2` | Reemplazar la configuración SAML                     |

<Note>
  `getSAMLSettings` (v1, sin el sufijo `V2`) y `updateSAMLSettings` (v1) están **obsoletos**. Usa los endpoints V2 que se muestran en esta guía.
</Note>

## Leer la configuración SAML actual

Obtén la configuración actual para poder compararla con la que pretendes enviar, o para confirmar que una actualización anterior se aplicó.

<CodeGroup>
  ```python Python theme={null}
  import requests

  headers = {
      "x-auth-scheme": "api-token",
      "x-auth-apikey": "YOUR_API_KEY",
      "Content-Type": "application/json",
  }

  response = requests.post(
      "https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
      headers=headers,
      json={},
  )

  for setting in response.json().get("samlSettings", []):
      print(f"team={setting.get('teamName')} enabled={setting.get('enabled')} "
            f"jit={setting.get('justInTimeAccountProvisioningEnabled')}")
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
    {
      method: "POST",
      headers: {
        "x-auth-scheme": "api-token",
        "x-auth-apikey": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({}),
    }
  );

  const { samlSettings = [] } = await response.json();
  for (const s of samlSettings) {
    console.log(`team=${s.teamName} enabled=${s.enabled} jit=${s.justInTimeAccountProvisioningEnabled}`);
  }
  ```

  ```go Go theme={null}
  req, _ := http.NewRequest("POST",
      "https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
      strings.NewReader("{}"))
  req.Header.Set("x-auth-scheme", "api-token")
  req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
  req.Header.Set("Content-Type", "application/json")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  var result struct {
      SamlSettings []struct {
          TeamName                              string `json:"teamName"`
          Enabled                               bool   `json:"enabled"`
          JustInTimeAccountProvisioningEnabled  bool   `json:"justInTimeAccountProvisioningEnabled"`
      } `json:"samlSettings"`
  }
  json.NewDecoder(resp.Body).Decode(&result)
  ```
</CodeGroup>

La respuesta contiene un array `samlSettings`. La mayoría de las organizaciones tienen una sola entrada; una segunda entrada existe únicamente para implementaciones que abarcan tanto el dominio `rhombus.com` como `rhombussystems.com`.

## Configurar SAML

`POST /api/org/updateSAMLSettingsV2` reemplaza la configuración SAML de la organización. Incluye las entradas que quieres que existan después de la llamada; los campos omitidos dentro de una entrada vuelven a sus valores predeterminados.

### Los campos de `OrgSamlSettingsType`

| Campo                                  | Tipo    | Descripción                                                                                                                                                                 |
| -------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`                              | boolean | Activa o desactiva el inicio de sesión SAML. Establécelo en `false` para deshabilitar SSO sin perder tus metadatos.                                                         |
| `idpMetaDataXml`                       | string  | El XML de metadatos SAML sin procesar de tu IdP (descriptor de entidad, certificado de firma, URLs de SSO).                                                                 |
| `justInTimeAccountProvisioningEnabled` | boolean | Si es `true`, se crea automáticamente un usuario de Rhombus la primera vez que alguien inicia sesión vía SAML. Consulta [JIT vs SCIM](#jit-vs-scim) más abajo.              |
| `enabledForRhombusKey`                 | boolean | Requerir SAML también para la aplicación de acceso móvil Rhombus Key.                                                                                                       |
| `addUsersOnRoleMismatch`               | boolean | Si es `true`, el inicio de sesión tiene éxito incluso cuando el rol declarado por el IdP no coincide con un rol de Rhombus; el usuario se agrega con un rol predeterminado. |
| `teamName`                             | string  | Etiqueta de visualización usada en la Consola.                                                                                                                              |
| `domain`                               | enum    | `RHOMBUS_COM` o `RHOMBUS_SYSTEMS_COM`. La mayoría de los clientes usan `RHOMBUS_COM`.                                                                                       |
| `rhombusKeyAppSettings`                | object  | Conmutadores por aplicación para la app móvil Rhombus Key (desbloqueo remoto, omisión de SAML para móvil, etc.).                                                            |

### Subir los metadatos del IdP

<CodeGroup>
  ```python Python theme={null}
  import requests

  # Read your IdP's federation metadata XML
  with open("idp-metadata.xml", "r") as f:
      idp_metadata_xml = f.read()

  headers = {
      "x-auth-scheme": "api-token",
      "x-auth-apikey": "YOUR_API_KEY",
      "Content-Type": "application/json",
  }

  body = {
      "samlSettings": [
          {
              "enabled": True,
              "idpMetaDataXml": idp_metadata_xml,
              "justInTimeAccountProvisioningEnabled": True,
              "enabledForRhombusKey": True,
              "addUsersOnRoleMismatch": False,
              "teamName": "Acme Corp",
              "domain": "RHOMBUS_COM",
          }
      ]
  }

  response = requests.post(
      "https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
      headers=headers,
      json=body,
  )
  response.raise_for_status()
  print("SAML configuration updated.")
  ```

  ```javascript JavaScript theme={null}
  import fs from "node:fs/promises";

  const idpMetadataXml = await fs.readFile("idp-metadata.xml", "utf8");

  const response = await fetch(
    "https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
    {
      method: "POST",
      headers: {
        "x-auth-scheme": "api-token",
        "x-auth-apikey": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        samlSettings: [
          {
            enabled: true,
            idpMetaDataXml: idpMetadataXml,
            justInTimeAccountProvisioningEnabled: true,
            enabledForRhombusKey: true,
            addUsersOnRoleMismatch: false,
            teamName: "Acme Corp",
            domain: "RHOMBUS_COM",
          },
        ],
      }),
    }
  );

  if (!response.ok) throw new Error(`Update failed: ${await response.text()}`);
  console.log("SAML configuration updated.");
  ```

  ```go Go theme={null}
  xmlBytes, _ := os.ReadFile("idp-metadata.xml")

  body, _ := json.Marshal(map[string]any{
      "samlSettings": []map[string]any{
          {
              "enabled":                              true,
              "idpMetaDataXml":                       string(xmlBytes),
              "justInTimeAccountProvisioningEnabled": true,
              "enabledForRhombusKey":                 true,
              "addUsersOnRoleMismatch":               false,
              "teamName":                             "Acme Corp",
              "domain":                               "RHOMBUS_COM",
          },
      },
  })

  req, _ := http.NewRequest("POST",
      "https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
      bytes.NewReader(body))
  req.Header.Set("x-auth-scheme", "api-token")
  req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
  req.Header.Set("Content-Type", "application/json")

  resp, err := http.DefaultClient.Do(req)
  if err != nil || resp.StatusCode != 200 {
      // handle error
  }
  ```
</CodeGroup>

<Warning>
  `updateSAMLSettingsV2` es una operación de **reemplazo**. Para cambiar un solo campo (por ejemplo, `teamName`), lee primero la configuración actual, modifica la entrada que quieras y vuelve a enviar el array completo. Omitir una entrada que existía previamente la elimina.
</Warning>

## JIT vs SCIM

Tienes dos opciones para incorporar usuarios a Rhombus:

| Opción                                                 | Qué hace                                                                                         | Cuándo elegirla                                                                                                                    |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| **JIT** (`justInTimeAccountProvisioningEnabled: true`) | Se crea un registro de usuario de Rhombus la primera vez que una persona inicia sesión vía SAML. | Equipos pequeños, baja rotación, SCIM no disponible en el nivel de tu IdP.                                                         |
| **SCIM** ([Parte 2](#configuración-inicial-de-scim))   | Tu IdP envía eventos de creación, actualización y desactivación a Rhombus a medida que ocurren.  | Organizaciones más grandes, requisitos de desaprovisionamiento por cumplimiento, cambios de rol que deben propagarse de inmediato. |

Puedes habilitar ambos: JIT gestiona a cualquier usuario que inicie sesión antes de que SCIM lo sincronice, y SCIM mantiene el directorio coherente a partir de entonces. La mayoría de las implementaciones en producción ejecutan ambos.

## Rotar los metadatos del IdP

Los certificados de firma del IdP rotan. Crea un trabajo programado que obtenga metadatos actualizados de tu IdP y los envíe a Rhombus; Rhombus sigue aceptando aserciones firmadas con el certificado antiguo hasta que reemplaces los metadatos.

```python Python theme={null}
import requests

def rotate_saml_metadata(api_key: str, new_metadata_xml: str) -> None:
    """Fetch current SAML settings, swap in new IdP metadata, push back."""
    headers = {
        "x-auth-scheme": "api-token",
        "x-auth-apikey": api_key,
        "Content-Type": "application/json",
    }

    # 1. Read current settings
    current = requests.post(
        "https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
        headers=headers,
        json={},
    ).json()

    settings = current.get("samlSettings") or []
    if not settings:
        raise RuntimeError("No existing SAML settings to rotate.")

    # 2. Replace the metadata XML on each entry; leave other fields untouched
    for entry in settings:
        entry["idpMetaDataXml"] = new_metadata_xml

    # 3. Push back
    response = requests.post(
        "https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
        headers=headers,
        json={"samlSettings": settings},
    )
    response.raise_for_status()
```

<Tip>
  Programa la rotación con bastante antelación a que el certificado de tu IdP realmente caduque. Verifica un inicio de sesión real inmediatamente después de la rotación, antes de cerrar la ventana de mantenimiento: una actualización de XML mal formada puede impedir los inicios de sesión hasta que reviertas.
</Tip>

## Acceso break-glass

**Antes de habilitar SAML, asegúrate de que al menos un usuario administrador tenga una contraseña nativa de Rhombus y pueda omitir SAML.** De lo contrario, una configuración incorrecta bloquea a todos y la única vía de recuperación es el Soporte de Rhombus.

Cada registro de usuario de Rhombus tiene un booleano `bypassSaml`. Mantén una o dos cuentas de administrador con `bypassSaml: true` como vía de recuperación. Estas cuentas deberían:

* Usar contraseñas fuertes y únicas almacenadas en tu gestor de secretos
* Tener MFA habilitado
* Auditarse con regularidad: trátalas como credenciales de root

<Warning>
  Nunca deshabilites SAML **y** elimines todas las cuentas break-glass en el mismo cambio. Prueba tu vía de recuperación al menos una vez por trimestre.
</Warning>

***

# Parte 2: Aprovisionamiento SCIM

SCIM (System for Cross-domain Identity Management) permite que tu IdP envíe eventos del ciclo de vida de los usuarios directamente a Rhombus, sin necesidad de iniciar sesión.

Cinco endpoints cubren SCIM de principio a fin:

| Endpoint                                 | Propósito                                                                           |
| ---------------------------------------- | ----------------------------------------------------------------------------------- |
| `POST /api/org/getScimDisplayInfo`       | Obtener las URLs del endpoint SCIM para entregarlas a tu IdP                        |
| `POST /api/org/setupSCIMAccessForOrg`    | Configuración inicial de SCIM; devuelve un bearer token                             |
| `POST /api/org/findSCIMSettingsForOrg`   | Leer la configuración SCIM actual                                                   |
| `POST /api/org/updateSCIMSettingsForOrg` | Cambiar las opciones de SCIM (correos de bienvenida, comportamiento de roles, etc.) |
| `POST /api/org/revokeSCIMAccessForOrg`   | Invalidar el bearer token SCIM actual                                               |

## Obtener las URLs del endpoint SCIM

Tu IdP necesita dos datos para conectarse: la **URL del endpoint** y un **bearer token**. La URL del endpoint proviene de `getScimDisplayInfo`:

<CodeGroup>
  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api2.rhombussystems.com/api/org/getScimDisplayInfo",
      headers={
          "x-auth-scheme": "api-token",
          "x-auth-apikey": "YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      json={},
  )

  info = response.json()
  print("Standard SCIM endpoint:", info["scimEndpointUrl"])
  print("Azure AD SCIM endpoint:", info["azureScimEndpointUrl"])
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api2.rhombussystems.com/api/org/getScimDisplayInfo",
    {
      method: "POST",
      headers: {
        "x-auth-scheme": "api-token",
        "x-auth-apikey": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({}),
    }
  );

  const info = await response.json();
  console.log("Standard SCIM endpoint:", info.scimEndpointUrl);
  console.log("Azure AD SCIM endpoint:", info.azureScimEndpointUrl);
  ```

  ```go Go theme={null}
  req, _ := http.NewRequest("POST",
      "https://api2.rhombussystems.com/api/org/getScimDisplayInfo",
      strings.NewReader("{}"))
  req.Header.Set("x-auth-scheme", "api-token")
  req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
  req.Header.Set("Content-Type", "application/json")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  var info struct {
      ScimEndpointUrl      string `json:"scimEndpointUrl"`
      AzureScimEndpointUrl string `json:"azureScimEndpointUrl"`
  }
  json.NewDecoder(resp.Body).Decode(&info)
  ```
</CodeGroup>

La mayoría de los IdP usan `scimEndpointUrl`. Azure AD / Entra requiere la variante específica de Azure debido a peculiaridades del esquema propias de Microsoft.

## Configuración inicial de SCIM

La primera llamada aprovisiona un bearer token. **Este token se muestra una sola vez y no se puede recuperar después**: captúralo de inmediato en tu gestor de secretos.

<CodeGroup>
  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
      headers={
          "x-auth-scheme": "api-token",
          "x-auth-apikey": "YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      json={
          "sendWelcomeEmailToNewUsers": True,
          "sendWelcomeEmailToNewRhombusKeyUsers": True,
          "addUsersOnRoleMismatch": False,
      },
  )

  data = response.json()
  if data.get("scimAccessAlreadySetupFailure"):
      raise RuntimeError("SCIM is already set up — revoke first or use update.")

  scim_bearer_token = data["token"]
  # Store scim_bearer_token in your secrets manager immediately.
  # Paste it into your IdP's SCIM provisioning settings as the bearer token.
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
    {
      method: "POST",
      headers: {
        "x-auth-scheme": "api-token",
        "x-auth-apikey": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        sendWelcomeEmailToNewUsers: true,
        sendWelcomeEmailToNewRhombusKeyUsers: true,
        addUsersOnRoleMismatch: false,
      }),
    }
  );

  const data = await response.json();
  if (data.scimAccessAlreadySetupFailure) {
    throw new Error("SCIM is already set up — revoke first or use update.");
  }

  const scimBearerToken = data.token;
  // Store scimBearerToken in your secrets manager immediately.
  ```

  ```go Go theme={null}
  body, _ := json.Marshal(map[string]any{
      "sendWelcomeEmailToNewUsers":           true,
      "sendWelcomeEmailToNewRhombusKeyUsers": true,
      "addUsersOnRoleMismatch":               false,
  })

  req, _ := http.NewRequest("POST",
      "https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
      bytes.NewReader(body))
  req.Header.Set("x-auth-scheme", "api-token")
  req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
  req.Header.Set("Content-Type", "application/json")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  var data struct {
      Token                        string `json:"token"`
      ScimAccessAlreadySetupFailure bool   `json:"scimAccessAlreadySetupFailure"`
  }
  json.NewDecoder(resp.Body).Decode(&data)
  // Store data.Token in your secrets manager immediately.
  ```
</CodeGroup>

<Warning>
  El bearer token SCIM se muestra **una sola vez**. Perderlo significa revocar el acceso actual y configurar de nuevo, y tu IdP pierde la sincronización hasta que se actualice su token.
</Warning>

### Opciones de configuración

| Campo                                  | Tipo    | Descripción                                                                               |
| -------------------------------------- | ------- | ----------------------------------------------------------------------------------------- |
| `sendWelcomeEmailToNewUsers`           | boolean | Enviar un correo a los nuevos usuarios cuando SCIM crea su cuenta de Rhombus.             |
| `sendWelcomeEmailToNewRhombusKeyUsers` | boolean | Lo mismo, pero para los usuarios agregados a la app de acceso móvil Rhombus Key.          |
| `addUsersOnRoleMismatch`               | boolean | Crear el usuario de todos modos si el rol declarado por el IdP no se mapea correctamente. |
| `rhombusKeyAppSettings`                | object  | Conmutadores por aplicación para el aprovisionamiento de Rhombus Key.                     |

## Leer la configuración SCIM actual

`findSCIMSettingsForOrg` devuelve el registro `SCIMSettingsType` completo, incluyendo la configuración de **formato de roles**, que importa para la compatibilidad con el IdP:

<CodeGroup>
  ```python Python theme={null}
  response = requests.post(
      "https://api2.rhombussystems.com/api/org/findSCIMSettingsForOrg",
      headers=headers,
      json={},
  )

  settings = response.json().get("scimSettings", {})
  print("rolesFormat:", settings.get("rolesFormat"))  # LIST_OF_STRINGS or LIST_OF_MULTI_VALUED_ATTRIBUTES
  print("welcome emails:", settings.get("sendWelcomeEmailToNewUsers"))
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api2.rhombussystems.com/api/org/findSCIMSettingsForOrg",
    { method: "POST", headers, body: "{}" }
  );
  const { scimSettings = {} } = await response.json();
  console.log("rolesFormat:", scimSettings.rolesFormat);
  ```

  ```go Go theme={null}
  req, _ := http.NewRequest("POST",
      "https://api2.rhombussystems.com/api/org/findSCIMSettingsForOrg",
      strings.NewReader("{}"))
  req.Header.Set("x-auth-scheme", "api-token")
  req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
  req.Header.Set("Content-Type", "application/json")
  // ... decode response.scimSettings
  ```
</CodeGroup>

### Compatibilidad de formato de roles

Rhombus acepta aserciones de roles SCIM en dos formas mediante `rolesFormat`:

| Valor                             | Forma                                                | IdP típico             |
| --------------------------------- | ---------------------------------------------------- | ---------------------- |
| `LIST_OF_STRINGS`                 | `"roles": ["admin", "viewer"]`                       | Okta, OneLogin, Google |
| `LIST_OF_MULTI_VALUED_ATTRIBUTES` | `"roles": [{"value": "admin"}, {"value": "viewer"}]` | Azure AD / Entra       |

Si los usuarios se están creando pero sus roles no se asignan correctamente, verifica esta configuración contra lo que tu IdP envía realmente.

## Actualizar la configuración SCIM

`updateSCIMSettingsForOrg` cambia el comportamiento de SCIM sin volver a emitir el bearer token:

```python Python theme={null}
response = requests.post(
    "https://api2.rhombussystems.com/api/org/updateSCIMSettingsForOrg",
    headers=headers,
    json={
        "sendWelcomeEmailToNewUsers": False,
        "sendWelcomeEmailToNewRhombusKeyUsers": True,
        "addUsersOnRoleMismatch": True,
    },
)
response.raise_for_status()
```

## Rotar o revocar el bearer token SCIM

Para rotar: **revoca y luego vuelve a configurar**. Tu IdP debe actualizarse con el nuevo token en la misma ventana de mantenimiento o el aprovisionamiento fallará.

<CodeGroup>
  ```python Python theme={null}
  # 1. Revoke current access
  requests.post(
      "https://api2.rhombussystems.com/api/org/revokeSCIMAccessForOrg",
      headers=headers,
      json={},
  ).raise_for_status()

  # 2. Issue a new token with the same options as before
  new = requests.post(
      "https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
      headers=headers,
      json={
          "sendWelcomeEmailToNewUsers": True,
          "sendWelcomeEmailToNewRhombusKeyUsers": True,
          "addUsersOnRoleMismatch": False,
      },
  ).json()

  new_token = new["token"]
  # 3. Push new_token into your IdP's SCIM bearer-token field.
  ```

  ```javascript JavaScript theme={null}
  // 1. Revoke
  await fetch("https://api2.rhombussystems.com/api/org/revokeSCIMAccessForOrg",
    { method: "POST", headers, body: "{}" });

  // 2. Re-issue
  const setupResp = await fetch(
    "https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
    {
      method: "POST",
      headers,
      body: JSON.stringify({
        sendWelcomeEmailToNewUsers: true,
        sendWelcomeEmailToNewRhombusKeyUsers: true,
        addUsersOnRoleMismatch: false,
      }),
    }
  );
  const { token: newToken } = await setupResp.json();
  // 3. Update IdP with newToken.
  ```

  ```go Go theme={null}
  revokeReq, _ := http.NewRequest("POST",
      "https://api2.rhombussystems.com/api/org/revokeSCIMAccessForOrg",
      strings.NewReader("{}"))
  // set headers, execute ...

  // Then setup again to get a new token (see earlier example).
  ```
</CodeGroup>

<Warning>
  Revocar SCIM detiene de inmediato la sincronización de usuarios desde tu IdP. Los usuarios existentes de Rhombus no se ven afectados: siguen activos y pueden seguir iniciando sesión vía SAML, pero cualquier cambio del IdP (nuevas contrataciones, usuarios desaprovisionados) no se propagará hasta que se restaure SCIM.
</Warning>

***

## Notas de configuración específicas por IdP

Las llamadas a la API anteriores son las mismas en todos los IdP. Lo que cambia es dónde pegar los valores de Rhombus en la consola de tu IdP. Estas notas recogen lo que los clientes necesitan con más frecuencia.

<Note>
  Las consolas de los IdP cambian su interfaz con frecuencia. Trátalas como puntos de partida y recurre a la propia documentación del IdP si un menú se ha movido.
</Note>

<AccordionGroup>
  <Accordion title="Okta">
    **SAML.** Crea una nueva aplicación **SAML 2.0**. Para la SSO URL y la Audience URI, usa los valores del SAML ACS de Rhombus de tu organización (visible en la Consola en **Settings → SSO / SAML**). Descarga el XML de metadatos del IdP de Okta desde la pestaña **Sign On** de la aplicación y pásalo a `updateSAMLSettingsV2` como `idpMetaDataXml`.

    **SCIM.** En la pestaña **Provisioning** de la app de Okta, selecciona **SCIM 2.0**. Establece la **SCIM connector base URL** en el `scimEndpointUrl` de `getScimDisplayInfo`. Establece **Authentication Mode** en **HTTP Header**, con `Authorization: Bearer <scim-token>`. Establece `rolesFormat` en `LIST_OF_STRINGS`.
  </Accordion>

  <Accordion title="Azure AD / Microsoft Entra">
    **SAML.** Crea una nueva **Enterprise Application** → **Non-gallery**. En **Single sign-on**, elige SAML e importa los metadatos SP de Rhombus. Descarga el **Federation Metadata XML** de Azure y pásalo a `updateSAMLSettingsV2`.

    **SCIM.** En **Provisioning**, elige **Automatic**. Usa la **`azureScimEndpointUrl`** (no el endpoint estándar) como Tenant URL, y pega el bearer token de `setupSCIMAccessForOrg` como Secret Token. Establece `rolesFormat` en **`LIST_OF_MULTI_VALUED_ATTRIBUTES`**: Azure envía las aserciones de roles en esta forma.
  </Accordion>

  <Accordion title="Google Workspace">
    **SAML.** Desde la Google Admin Console, agrega una app SAML personalizada dirigida a Rhombus. Descarga los metadatos del IdP de Google y pásalos a `updateSAMLSettingsV2`.

    **SCIM.** Google Workspace soporta SCIM para algunas apps mediante **Automated user provisioning**. Usa el `scimEndpointUrl` con autenticación de bearer token. Establece `rolesFormat` en `LIST_OF_STRINGS`.
  </Accordion>

  <Accordion title="OneLogin">
    **SAML.** Crea un nuevo conector SAML 2.0; configura la ACS URL y el Entity ID a partir de los metadatos SP de Rhombus. Descarga el XML de metadatos del IdP de OneLogin y pásalo a `updateSAMLSettingsV2`.

    **SCIM.** El aprovisionamiento SCIM v2 de OneLogin toma el `scimEndpointUrl` estándar y un bearer token. Establece `rolesFormat` en `LIST_OF_STRINGS`.
  </Accordion>
</AccordionGroup>

***

## Auditar eventos de SSO

Cada intento de inicio de sesión SAML, exitoso o fallido, se escribe en el registro de auditoría de Rhombus, al igual que los cambios en la propia configuración SAML. Obtén estos eventos mediante `POST /api/report/getAuditFeed`.

Tipos de eventos de auditoría relevantes para SSO:

| Tipo de evento              | Se dispara cuando                                             |
| --------------------------- | ------------------------------------------------------------- |
| `SAML_LOGIN_WEB`            | Un usuario inicia sesión correctamente vía SAML en la Consola |
| `SAML_LOGIN_FAILURE_WEB`    | Un inicio de sesión SAML falló en la Consola                  |
| `SAML_LOGIN_MOBILE`         | Un usuario inició sesión vía SAML en una app móvil de Rhombus |
| `SAML_LOGIN_FAILURE_MOBILE` | Un inicio de sesión SAML falló en una app móvil de Rhombus    |
| `RHOMBUS_KEY_SAML_LOGIN`    | Un usuario inició sesión vía SAML en la app móvil Rhombus Key |
| `UPDATE_INTEGRATION_SAML`   | La propia configuración SAML fue modificada                   |

<Tip>
  Envía los eventos `UPDATE_INTEGRATION_SAML` a tu SIEM para detectar cambios no autorizados en la configuración de SSO, y alerta ante cualquier pico de `SAML_LOGIN_FAILURE_*` para detectar rápidamente rotaciones rotas.
</Tip>

## Solución de problemas

<AccordionGroup>
  <Accordion title="`updateSAMLSettingsV2` tiene éxito pero los usuarios no pueden iniciar sesión">
    Lo más frecuente es un problema con el propio XML de metadatos en lugar de la llamada a la API.

    * **Verifica que el XML** esté bien formado y contenga un certificado de firma vigente: un certificado caducado en los metadatos bloquea toda aserción.
    * **Verifica que el entity ID** en los metadatos coincida con lo que Rhombus espera (visible en la Consola en **Settings → SSO**).
    * **Verifica que JIT esté habilitado** si este es el primer inicio de sesión de estos usuarios y SCIM aún no los ha sincronizado; de lo contrario Rhombus no tiene ningún usuario al que mapear la aserción.
    * **Revisa los eventos de auditoría `UPDATE_INTEGRATION_SAML`** para confirmar que el cambio se aplicó como se esperaba.
  </Accordion>

  <Accordion title="Los usuarios SCIM se crean pero sus roles son incorrectos">
    Esto casi siempre es un desajuste de `rolesFormat`. Llama a `findSCIMSettingsForOrg`, verifica el valor y compáralo con la [tabla de compatibilidad de formato de roles](#compatibilidad-de-formato-de-roles). Azure AD necesita `LIST_OF_MULTI_VALUED_ATTRIBUTES`; la mayoría de los demás necesitan `LIST_OF_STRINGS`.
  </Accordion>

  <Accordion title="La configuración de SCIM devuelve `scimAccessAlreadySetupFailure: true`">
    SCIM ya está configurado. Puedes (a) llamar a `revokeSCIMAccessForOrg` y volver a ejecutar la configuración para obtener un token nuevo, o (b) llamar a `updateSCIMSettingsForOrg` para modificar las opciones sin tocar el token.
  </Accordion>

  <Accordion title="El aprovisionamiento SCIM dejó de funcionar tras la rotación">
    El IdP sigue usando el bearer token antiguo. Después de `revokeSCIMAccessForOrg` + un nuevo `setupSCIMAccessForOrg`, el nuevo token **debe** pegarse en la configuración de aprovisionamiento del IdP. Haz ambas cosas en una sola ventana de mantenimiento para evitar una brecha de sincronización.
  </Accordion>

  <Accordion title="Bloqueado fuera de SAML — no puedes iniciar sesión, no tienes una API key a mano">
    Usa una cuenta break-glass con `bypassSaml: true` y una contraseña nativa de Rhombus. Si no existe ninguna, contacta al Soporte de Rhombus. Por eso el [acceso break-glass](#acceso-break-glass) es un requisito previo, no algo deseable.
  </Accordion>

  <Accordion title="JIT crea usuarios sin rol">
    Establece `addUsersOnRoleMismatch: false` para rechazar a los usuarios cuyo rol del IdP no se mapea, obligando al operador del IdP a corregir la aserción. Establécelo en `true` si prefieres crear el usuario y asignar un rol en Rhombus después. Elige de forma deliberada: los dos comportamientos son mutuamente excluyentes.
  </Accordion>
</AccordionGroup>

## Próximos pasos

<Columns cols={2}>
  <Card title="Iniciar sesión con Rhombus" icon="key" href="/es/oauth-authentication">
    Crea aplicaciones de terceros que autentiquen a usuarios de Rhombus (OAuth 2.0, separado del SSO para empleados)
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/overview">
    Esquema completo de cada endpoint usado en esta guía (tag Org)
  </Card>

  <Card title="Límites de tasa" icon="gauge" href="/es/rate-limits">
    Comprende los límites de solicitudes para rotaciones y auditorías programadas
  </Card>

  <Card title="Comunidad de desarrolladores" icon="users" href="https://rhombus.community">
    Haz preguntas sobre SSO y comparte consejos de configuración específicos por IdP
  </Card>
</Columns>
