Skip to content

Keycloak — Configuración Fase 1

Realm: iris · Host: https://auth.huellagenica.com


1. Realm roles

Roles nativos de Postgres creados en Realm roles:

anon
patient
employee
org_member
bioinformatician
iris_admin

Roles simples, no composite. Se asignan directamente desde los grupos.


2. Grupos y atributos

Jerarquía de grupos creada en Groups:

/iris-internal/

Subgrupo Atributos Realm role asignado
bioinformatician all_orgs=false bioinformatician
bioinformatician-admin all_orgs=true bioinformatician
employee employee

/orgs/

Grupo padre sin subgrupos ni atributos. Los subgrupos se crean dinámicamente desde iris.api vía Keycloak Admin API cuando se registra una organización.

Estructura dinámica por org:

/orgs/{org_id}/
  admin       → sub_role=admin,     org_id={id},  realm role: org_member
  clinician   → sub_role=clinician,  org_id={id},  realm role: org_member
  requester   → sub_role=requester,  org_id={id},  realm role: org_member
  viewer      → sub_role=viewer,     org_id={id},  realm role: org_member

/patients/

Grupo raíz sin subgrupos.

Grupo Realm role asignado
patients patient

3. Protocol Mappers

Configurados en Client scopesrolesMappers. Se heredan en todos los clients del realm.

Mappers existentes (por defecto — no modificar)

Name Type Notas
audience resolve Audience Resolve intacto
client roles User Client Role intacto
realm roles User Realm Role Token Claim Name: role, Multivalued: Off, Claim JSON Type: String

El mapper realm roles ya venía configurado correctamente con Token Claim Name: role. PostgREST requiere el claim role en el nivel raíz como string simple, no como array anidado.

Mappers creados (atributos custom)

Name Type Token Claim Name Claim JSON Type Multivalued
org_id User Attribute org_id long OFF
sub_role User Attribute sub_role String OFF
all_orgs User Attribute all_orgs boolean OFF
patient_id User Attribute patient_id long OFF

Todos con Add to ID token: ON, Add to access token: ON, Add to userinfo: ON.


4. Clients

iris-api — Resource server

Campo Valor
Client type OpenID Connect
Client authentication ON
Standard flow OFF
Direct access grants OFF
Service accounts roles OFF
Device Authorization Grant OFF

Bearer-only. Solo valida tokens, nunca inicia flujos de login.

iris-genomics-cli — CLI + pipelines

Campo Valor
Client type OpenID Connect
Client authentication ON
Standard flow OFF
Direct access grants OFF
Service accounts roles ON
Device Authorization Grant ON

Service accounts roles: ON habilita client_credentials para pipelines automatizados. Device Authorization Grant: ON habilita device_flow para uso interactivo en terminal.

backapp-genomics — BACKAPP genómica

Campo Valor
Client type OpenID Connect
Client authentication ON
Standard flow ON
Root URL http://localhost:8081
Valid redirect URIs http://localhost:8081/*
Web origins http://localhost:8081

backapp-erm — BACKAPP ERM

Campo Valor
Client type OpenID Connect
Client authentication ON
Standard flow ON
Root URL http://localhost:8082
Valid redirect URIs http://localhost:8082/*
Web origins http://localhost:8082

crm — CRM

Campo Valor
Client type OpenID Connect
Client authentication ON
Standard flow ON
Root URL http://localhost:8083
Valid redirect URIs http://localhost:8083/*
Web origins http://localhost:8083

5. Mapper de Audience por client

El claim aud debe incluir iris-api para que PostgREST valide correctamente los tokens. Se agrega como mapper en el dedicated scope de cada client (no en el realm).

Ruta: Clients{client}Client scopes{client}-dedicatedMappersAdd mapperAudience

Campo Valor
Name iris-api-audience
Included Client Audience iris-api
Add to ID token OFF
Add to access token ON

Aplicado en los siguientes clients:

  • iris-genomics-cli
  • backapp-genomics
  • backapp-erm
  • crm

6. Verificación del JWT

Token de prueba obtenido via device_flow con usuario test-bio (grupo /iris-internal/bioinformatician):

{
  "iss": "https://auth.huellagenica.com/realms/iris",
  "aud": ["iris-api", "account"],
  "azp": "iris-genomics-cli",
  "scope": "openid profile email",
  "role": "bioinformatician",
  "all_orgs": false,
  "email_verified": true,
  "preferred_username": "test-bio"
}

Claims validados

Claim Valor Estado
role bioinformatician ✅ realm role como string simple
all_orgs false ✅ atributo de grupo como boolean
aud ["iris-api", "account"] ✅ audience correcto para PostgREST
iss https://auth.huellagenica.com/realms/iris ✅ issuer correcto

org_id y sub_role ausentes en este token — esperado. El grupo /iris-internal/bioinformatician no tiene org_id asignado. Aparecerán cuando el usuario pertenezca a un subgrupo de /orgs/{org_id}/.


Comandos de prueba

Device flow (interactivo)

# Paso 1 — solicitar device code
curl -s -X POST \
  https://auth.huellagenica.com/realms/iris/protocol/openid-connect/auth/device \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=iris-genomics-cli" \
  -d "client_secret=<client_secret>" \
  -d "scope=openid"

# Abrir verification_uri_complete en el navegador y autenticarse

# Paso 2 — obtener y decodificar token
curl -s -X POST \
  https://auth.huellagenica.com/realms/iris/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "device_code=<device_code>" \
  -d "client_id=iris-genomics-cli" \
  -d "client_secret=<client_secret>" \
  | python3 -c "
import sys, json, base64
token = json.load(sys.stdin)['access_token']
payload = token.split('.')[1]
payload += '=' * (4 - len(payload) % 4)
print(json.dumps(json.loads(base64.b64decode(payload)), indent=2))
"

JWKS endpoint (clave pública para PostgREST)

curl -s https://auth.huellagenica.com/realms/iris/protocol/openid-connect/certs

OpenID discovery

curl -s https://auth.huellagenica.com/realms/iris/.well-known/openid-configuration