Praxsuite

Resource Grants

Vincent Depassier · 30 de agosto de 2026

Los row filters responden "qué filas puede ver esta persona". Los resource grants responden otra pregunta: ¿puede esta persona participar de esa cosa?

Un canal de chat. Un tablero. Una llamada. Un hilo de documento. Son objetos que inventó tu app, y la plataforma no tiene idea de qué son — pero igual tiene que controlar el acceso, porque el Event Bus y las llamadas necesitan saber quién puede entrar.


Por qué existe esto

La alternativa se probó y falló de una forma instructiva.

El hub de tiempo real respondía "¿puede este usuario final entrar a este canal?" leyendo tres tablas concretas de una app concreta. Eso significaba que el primitivo de tiempo real supuestamente genérico funcionaba para exactamente un producto, y negaba en silencio toda suscripción de todos los demás.

Praxsuite es la plataforma; una app construida sobre ella es un tenant. Los nombres de tabla de un tenant no tienen nada que hacer dentro de la plataforma. Los resource grants son el arreglo: tu app declara quién puede alcanzar sus objetos, y la plataforma hace cumplir esa declaración sin enterarse nunca de qué es un "canal".

Por eso resourceType es un string libre que elegís vos — "channel", "board", "dm-thread" — y no un enum que mantenemos nosotros. La plataforma nunca debería necesitar un cambio de código para aprender un tipo nuevo de objeto.


La forma de un grant

  resourceType  +  resourceId  →  beneficiario  →  nivel de acceso
   "channel"       9f2c8ab1…      una persona      participate

Parte

Notas

resourceType

El nombre que tu app le da a este tipo de objeto. Se compara sin distinguir mayúsculas, así que Channel y channel no discrepan en silencio.

resourceId

El objeto puntual — un UUID que apunta a una fila de tu propia tabla. Sin foreign key, a propósito.

Beneficiario

role, endUser, o any

Nivel de acceso

read, participate (por defecto), o manage

any significa todos los usuarios finales autenticados de tu app, dicho explícitamente. No es lo mismo que no tener ningún grant: la ausencia de grants significa denegado, nunca público.


La API

POST   /{workspaceId}/resources/{resourceType}/{resourceId}/grants   declarar uno
PUT    /{workspaceId}/resources/{resourceType}/{resourceId}/grants   reemplazar toda la lista
DELETE /{workspaceId}/resources/{resourceType}/{resourceId}/grants   revocar uno, o todos
GET    /{workspaceId}/resources/{resourceType}/{resourceId}/grants   leer la lista
POST https://gateway.praxsuite.com/{workspaceId}/resources/channel/9f2c8ab1-.../grants
Authorization: Bearer sk_live_xxxxxxxx

{ "grantee": "endUser", "endUserId": "…", "accessLevel": "participate" }

Las cuatro requieren una API key. Un token de usuario final se rechaza aunque autentique perfectamente — si no, cualquier persona logueada podría otorgarse a sí misma un recurso, y toda la lista de acceso sería decorativa. Declarar acceso es un acto administrativo, así que toma una credencial administrativa.

La lectura es solo con key por la misma razón: la lista de miembros de un canal privado no es algo que un miembro deba poder enumerar.


Preferí PUT

POST es idempotente por beneficiario, así que volver a declarar un grant existente no lo duplica. Pero PUT reemplaza toda la lista en una llamada, y eso es casi siempre lo que realmente querés.

La razón vale decirla: cuando cambia el acceso, volver a declarar la membresía completa del recurso es mucho más fácil de hacer bien que calcular qué grants agregar y quitar. Un diff calculado por cada app es un diff que cada app puede equivocar — y equivocarlo significa que alguien conserva un acceso que debería haber perdido.

Entonces: cuando cambia la membresía de un canal, mandá la membresía nueva. No calcules el delta.


Dónde se aplican

El Event Bus, para tópicos en modo Per bus: el segmento de instancia de la clave del bus es el resourceId, y entrar requiere read mientras que publicar requiere participate. Un recurso que declarás una vez queda alcanzable por todos los transportes, sin declarar nada dos veces.

El permiso se vuelve a verificar en cada publicación, no solo al entrar — así que revocar un grant expulsa a los peers que ya no califican en vez de dejar que un socket abierto sobreviva al chequeo que lo admitió.


Desde una automatización

La mayoría de las apps no llaman a esta API a mano. El nodo de automatización Manage Resource Grants lo hace como parte del mismo flujo que crea el objeto, que es el lugar correcto: el momento en que existe un canal es el momento en que se conoce su membresía.


Recomendaciones

  • Declará los grants cuando creás el recurso, en la misma automatización. Un recurso que existe sin grants es un recurso que nadie puede alcanzar — incluida la persona que acaba de crearlo.

  • Otorgá a roles cuando puedas. "Todos los que tengan el rol Soporte" sobrevive a los cambios de equipo; una lista de personas sueltas no.

  • Reafirmá, no calcules diferencias. PUT con la lista completa en cada cambio.

  • Acordate de que `manage` no es gratis. Es el nivel que le permite a un beneficiario cambiar la propia lista de acceso.


Siguiente