Appearance
Conceptos: cómo funciona la autenticación y el acceso a datos
Para configurar la integración de Sistema de salud es útil entender los estándares que participan. Esta página los explica de forma completa pero orientada a la operación: son los términos exactos (client_id, scope, JWK, RS384, etc.) que te van a pedir los sistemas externos.
OAuth 2.0
OAuth 2.0 es un marco de autorización (RFC 6749) que permite a una aplicación obtener acceso delegado a recursos protegidos sin compartir credenciales del usuario. Es el estándar que usan la mayoría de las APIs modernas (Google, GitHub, servicios de salud, etc.).
Actores
| Actor | Qué es | En esta integración |
|---|---|---|
| Resource owner | El dueño de los datos | La organización (y sus pacientes) |
| Client | La aplicación que quiere acceder a los datos | Quralo |
| Authorization server | Emite los tokens | El token endpoint del sistema de salud |
| Resource server | Guarda y sirve los datos | La API FHIR R4 del sistema de salud |
Piezas fundamentales
- Access token: un "pase" temporal que prueba que el cliente está autorizado a hacer una acción. Se envía en el header
Authorization: Bearer <token>. En este contexto es un JWT firmado. - Scope: el alcance o permiso otorgado al token (qué recursos puede leer, por ejemplo). Limita el "radio de acción" del token.
- Grant type: el método que usa el cliente para obtener el token. En esta integración se usa
client_credentials.
Tipos de grant (resumen)
OAuth 2.0 define varios flujos según el escenario:
| Grant | Uso típico | ¿Se usa acá? |
|---|---|---|
authorization_code | Aplicaciones con usuario que inicia sesión (ej. "Login con Google") | No |
implicit | SPA antiguas (deprecado) | No |
password | Confiar el usuario/password al cliente (desaconsejado) | No |
client_credentials | Comunicación máquina-a-máquina (M2M), sin usuario | Sí |
refresh_token | Renovar un access token que expiró | Derivado de otros flujos |
Client Credentials: el flujo M2M
Cuando dos sistemas se hablan sin un usuario humano de por medio (por ejemplo, Quralo consultando los datos del HIS), se usa el grant Client Credentials. El cliente se autentica contra el servidor de autorización presentando sus propias credenciales de cliente, y a cambio recibe un access token con los scopes solicitados.
En un OAuth "clásico" esas credenciales son un client_id + client_secret (una contraseña compartida). Pero compartir un secreto entre organizaciones es frágil: si se filtra, hay que rotarlo, y ambos lados deben guardarlo de forma segura.
La alternativa elegida: Private Key JWT
En lugar de un client_secret, la integración de Quralo usa Private Key JWT (RFC 7523): el cliente firma un JWT con su clave privada y se lo presenta al servidor de autorización. El servidor verifica la firma con la clave pública que la organización registró previamente.
Ventajas:
- No se comparte ningún secreto: la clave privada nunca viaja ni se expone.
- Firma criptográfica: la identidad se demuestra con criptografía de clave pública, no con una contraseña.
- Rotación controlada: se pueden regenerar los pares de claves sin coordinar un secreto nuevo con el proveedor.
¿Cómo se autentica el cliente?
Los métodos de autenticación de cliente que define OAuth 2.0 son variados (client_secret_basic, client_secret_post, tls_client_auth, private_key_jwt, etc.). SMART Backend Services exige private_key_jwt, que es el que implementa Quralo.
En el request de token, el cliente envía:
http
POST {token_endpoint}
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<JWT firmado>
&scope=system/Patient.read system/Observation.readclient_assertion_typeindica que la aserción es un JWT bearer.client_assertiones el JWT firmado con la clave privada del cliente.
Estructura del client assertion JWT
Un JWT tiene tres partes separadas por puntos: header.payload.signature. Cada parte está codificada en Base64URL.
Header (identifica el algoritmo y la clave usada para firmar):
json
{
"alg": "RS384",
"kid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"typ": "JWT"
}alg: algoritmo de firma. AcáRS384(RSA) oES384(EC P-384).kid: key ID, el identificador de la clave pública que el servidor debe usar para verificar. Es un UUID corto, estable por par de claves.
Payload (las afirmaciones sobre quién es el cliente):
json
{
"iss": "cliente_del_his",
"sub": "cliente_del_his",
"aud": "https://his.ejemplo.com/fhir/token",
"iat": 1737150000,
"exp": 1737150060,
"jti": "8f1c…"
}| Claim | Qué es |
|---|---|
iss (issuer) | Quién emite la aserción → el client_id |
sub (subject) | El sujeto → también el client_id |
aud (audience) | Para quién es → el token endpoint |
iat (issued at) | Fecha/hora de emisión (unix timestamp) |
exp (expiration) | Expiración (corta, típicamente 1-5 min) |
jti (JWT ID) | Identificador único de la aserción (anti-replay) |
Signature: el resultado de firmar header.payload con la clave privada. El servidor lo verifica usando la clave pública que la organización registró (identificada por el kid).
Claves y JWK / JWKS
Un JWK (JSON Web Key, RFC 7517) es la representación JSON de una clave criptográfica. Un JWKS (JSON Web Key Set) es una lista de claves: { "keys": [ ... ] }.
El JWK que Quralo te muestra para registrar incluye use: "sig" (la clave es para firmar/verificar firmas), alg, kid y el material criptográfico:
json
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"alg": "RS384",
"kid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"n": "…",
"e": "AQAB"
}
]
}Para EC P-384 (ES384) el formato usa crv, x e y:
json
{
"kty": "EC",
"use": "sig",
"alg": "ES384",
"kid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"crv": "P-384",
"x": "…",
"y": "…"
}Algoritmos de firma: RS384 y ES384
| Algoritmo | Tipo de clave | Observación |
|---|---|---|
| RS384 | RSA (≥ 2048 bits) | RSA con hash SHA-384. Es el recomendado y el default en Quralo. Ampliamente soportado. |
| ES384 | EC P-384 (curva elíptica) | ECDSA con hash SHA-384. Claves más cortas y firmas más pequeñas, pero requiere que el servidor externo lo soporte. |
SMART Backend Services exige uno de estos dos algoritmos (no acepta, por ejemplo, RS256). El que elijas debe coincidir con lo que espera tu sistema de salud.
SMART Backend Services
SMART (Substitutable Medical Applications, Reusable Technologies) es el estándar de interoperabilidad de aplicaciones clínicas sobre FHIR, impulsado por HL7 y Boston Children's Hospital. Tiene dos variantes:
- SMART App Launch: para aplicaciones que corren con un usuario que autoriza (flujo
authorization_code). - SMART Backend Services: para comunicación servidor a servidor (M2M) sin usuario, que es exactamente el caso de la integración de Quralo.
SMART Backend Services define:
- Autenticación del cliente:
client_credentials+private_key_jwtcon RS384 o ES384 (lo que ya vimos). - Scopes con formato
system/{recurso}.{operación}(ej.system/Patient.read). El prefijosystem/indica que el token actúa "a nombre del sistema", no de un usuario. - Descubrimiento: el servidor FHIR puede publicar su configuración en
.well-known/smart-configuration, donde se anuncian el token endpoint, los scopes soportados y los algoritmos.
Descubrimiento del token endpoint
Si el sistema externo expone .well-known/smart-configuration, Quralo descubre automáticamente el token endpoint:
http
GET {fhir_base_url}/.well-known/smart-configurationjson
{
"token_endpoint": "https://his.ejemplo.com/fhir/token",
"capabilities": ["permission-v2"],
"scopes_supported": ["system/Patient.read", "system/*.read"],
"code_challenge_methods_supported": []
}Si tu sistema no expone este archivo, configurás el Token endpoint URL manualmente en la integración.
FHIR R4
FHIR (Fast Healthcare Interoperability Resources, HL7) es el estándar moderno para intercambiar datos de salud por API. La versión R4 (Release 4) es la 4.0.1 y es la que requiere esta integración.
Recursos
Los datos clínicos se modelan como recursos con estructura JSON. Algunos relevantes para los scopes de Quralo:
| Recurso | Qué representa |
|---|---|
Patient | Datos demográficos de un paciente |
Observation | Resultados y observaciones clínicas (laboratorio, signos vitales) |
DiagnosticReport | Informes de diagnóstico (imágenes, laboratorio) |
MedicationRequest | Prescripciones / solicitudes de medicación |
ServiceRequest | Solicitudes de servicio (estudios, procedimientos) |
Encounter | Encuentros clínicos (consultas, internaciones) |
CapabilityStatement | La "tarjeta de presentación" del servidor (qué soporta) |
Interacciones RESTful
FHIR R4 usa REST: GET, POST, PUT, DELETE sobre las colecciones de recursos (/Patient, /Observation, etc.). Esta integración consume principalmente lectura (interacciones read y search).
/metadata y el CapabilityStatement
Todo servidor FHIR debe responder en GET {base}/metadata con un CapabilityStatement: el documento que declara las capacidades del servidor (versión de FHIR, recursos soportados, seguridad, etc.).
El campo fhirVersion indica la versión del estándar. La verificación de Quralo exige que sea 4.0.1:
json
{
"resourceType": "CapabilityStatement",
"status": "active",
"fhirVersion": "4.0.1",
"rest": [
{
"mode": "server",
"resource": [ { "type": "Patient" }, { "type": "Observation" } ],
"security": { "service": [ { "coding": [ { "code": "SMART-on-FHIR" } ] } ] }
}
]
}La verificación consulta
/metadatacon el token (Authorization: Bearer <token>): así confirma que el token es aceptado contra la base FHIR correcta y que la versión es la exigida.
Scopes SMART sobre FHIR
Los scopes de lectura siguen el patrón system/{Recurso}.read (o system/*.read para todos los recursos). El servidor FHIR solo devuelve los recursos para los que el token tenga scope. El catálogo completo que podés configurar está en Scopes.
El flujo completo, de punta a punta
Resumen
- OAuth 2.0 es el marco de autorización; se usa el grant
client_credentials(M2M, sin usuario). - En lugar de un secreto compartido, el cliente se autentica con Private Key JWT: firma un JWT con su clave privada (
RS384oES384), que el servidor verifica con la clave pública registrada. - SMART Backend Services es el perfil de HL7 que exige este método y define los scopes
system/...y el descubrimiento por.well-known/smart-configuration. - FHIR R4 es la API de datos clínicos; la integración lee recursos y valida
fhirVersion == 4.0.1en/metadata.
Ahora que tenés el panorama completo, seguí con la Configuración paso a paso.