|
7 min de lectura
|

FHIR RBAC con Keycloak y SMART on FHIR v2

Resumir este artículo con:
ChatGPTPerplexityClaudeGrok

Construir aplicaciones sanitarias sobre un servidor FHIR se ha convertido en una práctica habitual. Los servidores FHIR proporcionan almacenamiento estandarizado y APIs para recursos clínicos, lo que permite a los desarrolladores centrarse en crear funcionalidades en lugar de gestionar la infraestructura de datos sanitarios. Sin embargo, esto plantea una pregunta importante: ¿cómo garantizar que los distintos usuarios vean únicamente los datos que tienen permitido ver?

Por ejemplo, un médico debería tener acceso completo a las observaciones del paciente — tanto los resultados de laboratorio como los signos vitales. Un técnico de laboratorio, por su parte, solo debería ver los resultados de laboratorio finalizados que sean relevantes para su trabajo. Implementar este tipo de control de acceso granular requiere tradicionalmente una lógica compleja a nivel de aplicación, reglas de autorización personalizadas y pruebas exhaustivas.

Existe una forma mejor: un enfoque basado en estándares que aprovecha su proveedor de identidad existente y no requiere ningún código de autorización personalizado en su aplicación.

En esta entrada, exploraremos cómo implementar un control de acceso basado en roles (RBAC) sofisticado para recursos FHIR utilizando roles de Keycloak (una solución de gestión de identidad y acceso de código abierto) mapeados a ámbitos de SMART on FHIR V2, con aplicación automática por parte de Aidbox. ¿Lo mejor? El mismo endpoint de API devuelve datos diferentes según quién realiza la consulta — de forma completamente transparente.

El problema: un endpoint, múltiples niveles de acceso

Imagine que está construyendo una aplicación sanitaria sobre el servidor FHIR con dos tipos de usuarios:

Dra. Sara (médico)

  • Necesita ver todas las observaciones del paciente
  • Revisa tanto los resultados de laboratorio como los signos vitales
  • Toma decisiones clínicas basándose en los datos completos del paciente

Miguel (técnico de laboratorio)

  • Trabaja únicamente con resultados de laboratorio finalizados
  • No debería ver los signos vitales ni los datos de laboratorio preliminares
  • Necesita un acceso limitado a su función laboral específica

Ambos usuarios llaman al mismo endpoint de la API: GET /fhir/Observation. Pero deberían ver resultados completamente diferentes.

Tradicionalmente, los desarrolladores resolverían esto añadiendo:

  • Middleware personalizado para verificar los roles del usuario
  • Filtros de consulta complejos en el código de la aplicación
  • Endpoints de API separados o parámetros distintos para diferentes tipos de usuarios
  • Pruebas unitarias exhaustivas para cada escenario de autorización
  • Problemas de mantenimiento a medida que evolucionan los requisitos

Este enfoque funciona, pero es difícil de mantener y propenso a errores conforme los requisitos evolucionan. Existe una forma mejor.

La solución: los ámbitos SMART se combinan con los roles de Keycloak

SMART on FHIR V2 introduce un concepto poderoso: ámbitos con parámetros de consulta. En lugar de otorgar simplemente un acceso amplio como «este usuario puede leer Observations», puede especificar reglas exactas, como:

user/Observation.rs?category=laboratory&status=final

Este ámbito significa: «El usuario puede leer y buscar Observations, pero solo observaciones de laboratorio con estado final».

Combinando esto con el sistema de roles compuestos de Keycloak, podemos:

  • Definir permisos granulares como roles básicos de Keycloak (cada uno representando un ámbito SMART)
  • Agruparlos en funciones laborales mediante roles compuestos (como «physician» o «lab_technician»)
  • Resolver automáticamente los roles compuestos en ámbitos SMART dentro del token de acceso
  • Dejar que Aidbox aplique las reglas automáticamente — sin necesidad de código personalizado

Así funciona el flujo:

User Login → Keycloak resolves roles → Token with SMART scopes →
Aidbox validates token → Automatic data filtering → Correct results

Implementación: construcción de la estructura de roles

Paso 1: definir los roles básicos (ámbitos SMART granulares)

En Keycloak, creamos roles básicos que se mapean directamente a ámbitos de SMART on FHIR V2:

Roles básicos:

  • user/Patient.rs - Leer y buscar datos de pacientes
  • user/Encounter.rs - Leer y buscar encuentros
  • user/Observation.rs - Leer y buscar TODAS las observaciones
  • user/Observation.rs?category=laboratory&status=final - Leer y buscar ÚNICAMENTE resultados de laboratorio finalizados

Estos roles básicos son los bloques de construcción. Cada uno representa un permiso específico con restricciones opcionales de parámetros de consulta.

Paso 2: crear roles compuestos (funciones laborales)

A continuación, combine los roles básicos en roles compuestos que reflejen las funciones laborales reales:

Rol de médico (acceso clínico completo):

  • user/Patient.rs
  • user/Encounter.rs
  • user/Observation.rs

Rol de técnico de laboratorio (limitado a resultados de laboratorio):

  • user/Patient.rs
  • user/Observation.rs?category=laboratory&status=final

Observe que el rol de técnico de laboratorio utiliza el ámbito de Observation restringido — impidiendo el acceso a los signos vitales o a los resultados preliminares.

Paso 3: configurar el mapeador de tokens

Aquí es donde ocurre la magia. Keycloak convierte los roles en tokens de acceso. El token es un archivo pequeño y seguro (JSON Web Token — JWT) que viaja con cada solicitud de API y le indica a Aidbox qué tiene permitido hacer el usuario. Necesitamos que Keycloak:

  • Resuelva los roles compuestos (p. ej., «physician») en sus roles básicos constituyentes
  • Incluya esos roles básicos en el claim scope del token como ámbitos SMART
  • Añada el claim atv: "2" para indicar que hay ámbitos SMART on FHIR en el token que deben procesarse

Esto lo conseguimos mediante un mapeador de protocolo basado en scripts personalizado. Cuando un técnico de laboratorio inicia sesión, su token de acceso tiene este aspecto:

{
  "sub": "lab_technician",
  "scope": "user/Patient.rs 
            user/Observation.rs?category=laboratory&status=final",
  "atv": "2"
}

Paso 4: configurar Aidbox para la aplicación automática

Aquí está la parte más elegante: Aidbox aplica automáticamente las reglas de acceso definidas en el token. Todo lo que necesita es:

  • TokenIntrospector - Verifica que el token es válido y fue emitido por su instancia de Keycloak:
{
  "resourceType": "TokenIntrospector",
  "jwt": {
    "iss": "http://localhost:8888/realms/master"
  },
  "type": "jwt",
  "jwks_uri": 
    "http://keycloak:8888/realms/master/protocol/openid-connect/certs",
  "id": "external-auth-server",
  "resourceType": "TokenIntrospector"
}
  • AccessPolicy — Permite las solicitudes con tokens validados:
{
  "resourceType": "AccessPolicy",
  "id": "keycloak-access-policy",
  "engine": "matcho",
        "matcho": {
          "jwt": {
            "iss": "http://localhost:8888/realms/master"
          }
        }
}

Eso es todo. Cuando Aidbox recibe una solicitud con un token que contiene atv: "2" y ámbitos SMART, automáticamente:

  • Analiza los ámbitos para determinar los tipos de recursos permitidos
  • Aplica los filtros de parámetros de consulta derivados de los ámbitos
  • Devuelve únicamente los datos que coinciden con las restricciones del ámbito
  • Rechaza las solicitudes de tipos de recursos no autorizados

Sin código de autorización personalizado. Sin lógica de control de acceso compleja. Simplemente funciona.

Viéndolo en acción

Veamos ambos escenarios de usuario para comprobar cómo la misma llamada a la API devuelve resultados diferentes. Imagine que ha configurado su sistema con Aidbox conectado a Keycloak, y que tanto la Dra. Sara (la médico) como Miguel (el técnico de laboratorio) utilizan la misma aplicación.

En el sistema existen dos recursos Observation:

  • Hemoglobina — una observación de laboratorio con estado «final»
  • Tensión arterial — una observación de signos vitales

Ambos usuarios accederán al mismo endpoint: GET /fhir/Observation Pero Aidbox devolverá respuestas diferentes según quién realice la solicitud.

Prueba 1: acceso del médico (acceso completo)

Credenciales de inicio de sesión:

Username: physician
Password: password

Llamada a la API:

GET /fhir/Observation
Authorization: Bearer <physician_token>

Ámbitos del token:

user/Patient.rs user/Encounter.rs user/Observation.rs

Resultado: El médico ve ambas observaciones:

  • Hemoglobina (laboratorio, final)
  • Tensión arterial (signos vitales)

El ámbito user/Observation.rs concede acceso sin restricciones a todos los recursos Observation.

Prueba 2: acceso del técnico de laboratorio (acceso restringido)

Credenciales de inicio de sesión:

Username: lab_technician
Password: password

Llamada a la API:

GET /fhir/Observation
Authorization: Bearer <lab_technician_token>

Ámbitos del token:

user/Patient.rs 
user/Observation.rs?category=laboratory&status=final

Resultado: El técnico de laboratorio ve únicamente una observación:

  • Hemoglobina (laboratorio, final)

La observación de tensión arterial queda filtrada porque no cumple los requisitos del ámbito:

  • Su categoría es «vital-signs» (no «laboratory»)
  • El ámbito exige explícitamente category=laboratory&status=final

El mismo endpoint, el mismo código, resultados diferentes según quién realiza la consulta. Sin necesidad de lógica de filtrado personalizada.

Pruébelo usted mismo

¿Desea verlo en acción? El ejemplo completo está listo para ejecutarse con Docker.

Requisitos previos: Docker y Docker Compose instalados

Inicio rápido:

cd aidbox-features/smart-keycloak-roles
  • Inicie todos los servicios:
docker compose up --build

Inicie sesión como physician/password — vea todas las observaciones

  • Haga clic en «Start Over» e inicie sesión como lab_technician/password — vea solo los resultados de laboratorio

La aplicación de demostración muestra en paralelo a qué puede acceder cada usuario, haciendo que las diferencias de control de acceso sean inmediatamente visibles.

Conclusiones clave

Este enfoque ofrece varios beneficios significativos:

1. Cero código de autorización personalizado Su aplicación no necesita entender los roles ni implementar lógica de filtrado. Aidbox lo gestiona automáticamente basándose en los ámbitos SMART.

2. Control de acceso centralizado Todas las definiciones de roles residen en su proveedor de identidad (Keycloak). Cambie los permisos de un rol en un único lugar y se aplicará en todas partes.

3. Basado en estándares Construido sobre SMART on FHIR V2, un estándar consolidado de interoperabilidad sanitaria. Sin soluciones propietarias ni dependencia de un proveedor específico.

4. Control granular Las restricciones de parámetros de consulta (?category=laboratory&status=final) permiten un control de acceso preciso sin reglas personalizadas complejas.

5. Fácil de extender ¿Necesita un nuevo rol? Cree un rol compuesto en Keycloak combinando los roles básicos adecuados. No se requieren cambios en el código.

Más información:

Conclusión

El control de acceso granular para recursos FHIR no tiene por qué ser complicado. Combinando los ámbitos de SMART on FHIR V2, el sistema de roles compuestos de Keycloak y la aplicación automática de ámbitos de Aidbox, puede implementar un RBAC sofisticado sin escribir código de autorización personalizado.

El resultado: aplicaciones más seguras, mantenimiento más sencillo y una mejor alineación con los estándares de interoperabilidad sanitaria.

¿Listo para implementar el control de acceso basado en roles en su aplicación FHIR? Comience con el repositorio de ejemplo y personalice los roles para su caso de uso específico.

Compartir este artículo
Comments
Comments
Sign in
Loading comments...
Subscribe to our blog

Get the latest articles on FHIR, interoperability, and healthcare IT.