Tema 8

8. Autorización segura: roles, permisos, scopes y control de acceso granular

En una API, autenticar es solo el comienzo. El verdadero riesgo suele aparecer después, cuando el sistema debe decidir qué puede hacer esa identidad sobre qué recurso, en qué contexto y con qué alcance. La autorización segura es la diferencia entre una API que reconoce usuarios y una API que realmente controla el acceso.

Objetivo Diseñar controles de acceso correctos y verificables
Enfoque Roles, permisos, scopes y contexto real de negocio
Resultado Evitar autorizaciones rotas y sobreexposición de privilegios

8.1 Introducción

Muchas APIs tienen autenticación correcta y aun así sufren incidentes graves porque autorizan mal. El sistema reconoce al actor, pero no valida adecuadamente si ese actor debería poder ver, modificar, borrar o ejecutar una acción específica sobre un recurso concreto.

Esto ocurre porque la autorización es más compleja que la autenticación. No solo depende de quién es el usuario, sino también del recurso, la operación, el rol, el tenant, el contexto de negocio, el canal, el momento y, a veces, la relación entre múltiples entidades.

Por eso este tema se centra en cómo modelar autorización de forma segura en APIs REST, evitando los errores que luego terminan en BOLA, BFLA, exposición de propiedades sensibles o abuso funcional.

8.2 Qué es autorización en una API

La autorización es el proceso por el cual la API decide si una identidad autenticada puede realizar una operación determinada sobre un recurso dado en un contexto específico. No es una sola verificación. Suele involucrar varias preguntas al mismo tiempo:

  • ¿Puede este actor acceder a este endpoint?
  • ¿Puede operar sobre este objeto concreto?
  • ¿Puede ver todos los campos o solo algunos?
  • ¿Puede ejecutar esta acción en este estado del negocio?
  • ¿Puede hacerlo dentro de este tenant, cuenta o proyecto?
En APIs maduras, la autorización no es un `if role == admin`. Es una política de acceso que se aplica de forma consistente a recursos, funciones y contexto.

8.3 Autorización gruesa y autorización fina

Una forma útil de pensar el problema es distinguir dos niveles:

  • Autorización gruesa: controla acceso general a una funcionalidad o grupo de endpoints.
  • Autorización fina: controla acceso al objeto concreto, a propiedades específicas y a condiciones de negocio.

Muchas APIs implementan solo el nivel grueso. Verifican que el usuario “tenga acceso al módulo”, pero no validan ownership, estado del recurso o campos permitidos. Ahí aparecen buena parte de las fallas graves.

8.4 Roles: utilidad y límites

Los roles son una forma común de agrupar capacidades. En vez de asignar permisos uno por uno a cada usuario, se define un conjunto de roles como `admin`, `operador`, `cliente`, `soporte` o `auditor`, y se asocia cada rol a ciertas acciones.

Esto simplifica la administración, pero tiene límites. Los roles funcionan bien para permisos relativamente estables y fáciles de agrupar. Cuando el dominio se vuelve complejo, confiar solo en roles suele llevar a dos problemas:

  • Roles demasiado amplios que otorgan más de lo necesario.
  • Explosión de roles porque se intenta representar cada caso particular con uno nuevo.

8.5 Permisos: unidades más precisas

Los permisos expresan acciones concretas, por ejemplo: `usuarios.leer`, `usuarios.editar`, `facturas.descargar`, `pedidos.cancelar`, `reportes.exportar`. Son más precisos que los roles porque permiten modelar capacidades específicas.

En muchos sistemas, los roles se usan como agrupadores de permisos. Eso suele ser una buena práctica, porque combina administración relativamente simple con granularidad razonable.

La clave es que la API tome decisiones a nivel de permiso real, no solo a nivel de etiqueta de rol.

8.6 Scopes: qué son y para qué sirven

Los scopes aparecen frecuentemente en sistemas con OAuth 2.0 y tokens. Representan el alcance del acceso concedido a un cliente o sesión. Un scope puede indicar que un token está autorizado para leer perfiles, consultar pedidos o administrar ciertos recursos.

Los scopes ayudan a limitar tokens y a expresar intención de acceso, pero no deberían verse como sustituto universal de la autorización completa. Un token con scope `pedidos:leer` todavía necesita pasar controles sobre qué pedidos puede ver realmente ese usuario o cliente.

El scope suele responder “qué tipo de acceso se concedió”. La autorización fina debe responder “sobre qué objetos y bajo qué condiciones puede ejercerse ese acceso”.

8.7 RBAC: control basado en roles

RBAC, o Role-Based Access Control, es uno de los modelos más usados. La lógica es directa: el acceso se decide según el rol o conjunto de roles del actor.

RBAC es útil cuando:

  • Los perfiles de acceso están relativamente bien definidos.
  • El número de variantes no es enorme.
  • Las reglas no dependen demasiado del estado del recurso o del contexto dinámico.

Sin embargo, RBAC se queda corto cuando el acceso depende de ownership, tenant, proyecto, horario, canal, ubicación o estado del negocio.

8.8 ABAC y políticas contextuales

ABAC, o Attribute-Based Access Control, toma decisiones usando atributos del actor, del recurso y del contexto. Por ejemplo, un usuario puede editar un documento si pertenece al mismo tenant, si es dueño del documento o si el documento sigue en estado borrador.

Este modelo es más expresivo que RBAC y suele representar mejor las necesidades reales de una API compleja. También es más difícil de implementar y probar si no se diseña con disciplina.

En la práctica, muchas APIs usan una mezcla: roles para una primera capa y atributos/contexto para la decisión fina.

8.9 Autorización a nivel de endpoint

La primera capa de control suele estar en el endpoint o la función. Aquí la API decide si un actor puede usar una operación general: por ejemplo, acceder a `/admin/reportes` o ejecutar `/usuarios/{id}/desactivar`.

Errores comunes en este nivel:

  • Proteger algunas rutas y olvidar variantes equivalentes.
  • Confiar en el frontend para ocultar acciones en lugar de bloquearlas en backend.
  • Aplicar middleware en rutas públicas, pero no en internas o legacy.
  • No separar claramente funciones de administración, soporte y cliente final.

8.10 Autorización a nivel de objeto

Incluso si el actor puede llamar al endpoint, todavía hay que decidir si puede operar sobre ese objeto concreto. Este es el núcleo de problemas como BOLA.

Ejemplos:

  • Un cliente puede ver sus pedidos, pero no los de otro cliente.
  • Un agente de soporte puede acceder a cuentas de su área, pero no a todas.
  • Un usuario puede modificar su perfil, pero no el de otros.

La verificación debe realizarse en backend y sobre el objeto real, no asumir que el identificador recibido ya corresponde a algo legítimo para ese actor.

8.11 Autorización a nivel de propiedad

No todo campo de un recurso debe ser visible o editable por todos los actores que pueden acceder al objeto. Aquí entran decisiones más finas:

  • Qué campos puede ver un cliente final.
  • Qué atributos solo ve soporte o auditoría.
  • Qué propiedades puede modificar el usuario y cuáles son internas.

Una API puede estar bien protegida a nivel de endpoint y objeto, pero seguir siendo insegura si permite leer flags internos, límites de cuenta, descuentos reservados o cambiar propiedades sensibles como `role`, `status` o `is_verified`.

8.12 Autorización según estado del negocio

Muchas decisiones de acceso dependen del estado del recurso. Por ejemplo, un pedido puede editarse mientras está pendiente, pero no después de facturado. Un documento puede borrarse en borrador, pero no cuando ya fue firmado. Un turno puede cancelarse hasta cierta hora, pero no después.

Si la API ignora el estado de negocio y solo revisa rol o permiso, abre la puerta a abuso funcional y operaciones incoherentes con las reglas del sistema.

La autorización no siempre es una cuestión de identidad. Muchas veces es una cuestión de momento y estado.

8.13 Tenants, cuentas y separación de contexto

En sistemas multi-tenant, la autorización debe incluir aislamiento entre organizaciones, cuentas o espacios de trabajo. Un usuario puede tener permiso para operar dentro de un tenant y no en otro, aunque su rol sea el mismo.

Problemas frecuentes en este punto:

  • Confiar en un `tenant_id` enviado por el cliente sin verificar membresía real.
  • Construir filtros de acceso de forma inconsistente entre endpoints.
  • Permitir exportaciones o búsquedas cruzadas sin aislamiento adecuado.
  • Usar el mismo token para múltiples contextos sin restricciones claras.

8.14 Mínimo privilegio en APIs

El principio de mínimo privilegio indica que cada actor debe tener solo los permisos necesarios para cumplir su función, y nada más. En APIs, esto se traduce en varios niveles:

  • Tokens con scopes acotados.
  • Roles lo más pequeños posible.
  • Clientes técnicos con acceso solo a las APIs que requieren.
  • Campos de respuesta limitados a lo estrictamente necesario.

El problema práctico es que muchas implementaciones sacrifican precisión para “simplificar”. Esa simplificación suele acumular deuda de seguridad y terminar en privilegios excesivos difíciles de retirar después.

8.15 Dónde implementar la lógica de autorización

La autorización puede aparecer en varios niveles: gateway, middleware, controlador, servicio de negocio o motor de políticas. Ninguna ubicación por sí sola resuelve todo.

Nivel Ventaja Límite
Gateway Aplica reglas generales comunes No suele conocer contexto fino del recurso
Middleware Estandariza chequeos iniciales Puede quedarse corto para lógica compleja
Servicio de negocio Ve estado real y reglas del dominio Puede dispersarse si no se centraliza criterio
Motor de políticas Centraliza y hace más auditable la decisión Agrega complejidad y requiere buena gobernanza

En general, los controles gruesos pueden estar antes; las decisiones finas deben vivir cerca del dominio real.

8.16 Errores comunes de diseño

  • Suponer que autenticación válida implica acceso válido.
  • Confiar en roles amplios sin permisos finos.
  • No validar ownership de objetos.
  • Permitir actualización masiva de campos sin lista explícita de propiedades autorizadas.
  • Codificar reglas dispersas e inconsistentes entre endpoints.
  • Hacer depender la autorización de datos enviados por el cliente.
  • No considerar estado del recurso ni contexto del negocio.

8.17 Cómo probar la autorización

La autorización no debería verificarse solo con pruebas felices. Conviene probar sistemáticamente combinaciones de actor, recurso y operación.

Casos clave:

  • Usuario correcto sobre recurso ajeno.
  • Rol bajo accediendo a función administrativa.
  • Actor legítimo intentando editar campos no permitidos.
  • Acceso dentro y fuera del tenant correcto.
  • Operaciones válidas sobre recursos en estados no permitidos.

Las pruebas de autorización deben cubrir no solo rutas, sino también payloads, filtros, relaciones y propiedades.

8.18 Observabilidad y auditoría de decisiones de acceso

Una API madura no solo toma decisiones de autorización. También puede explicarlas y auditarlas. Esto no significa exponer toda la lógica al cliente, sino registrar contexto suficiente para investigar incidentes y entender por qué una operación fue permitida o denegada.

Es útil registrar:

  • Identidad y tenant del actor.
  • Recurso y operación solicitada.
  • Resultado de la decisión.
  • Política o regla aplicada, cuando sea viable.
  • Contexto relevante como scopes, rol o estado del objeto.

8.19 Qué debes recordar de este tema

  • La autorización decide qué puede hacer una identidad autenticada sobre qué recurso y en qué contexto.
  • Roles, permisos y scopes son útiles, pero no sustituyen la validación fina por objeto, propiedad y estado.
  • Gran parte de las vulnerabilidades graves en APIs proviene de autorizaciones demasiado amplias o incompletas.
  • El mínimo privilegio debe aplicarse a endpoints, objetos, campos y contexto de negocio.
  • La autorización debe probarse y auditarse con el mismo rigor que la autenticación.

8.20 Conclusión

La autorización segura es uno de los pilares más críticos de una API REST porque traduce identidad en decisiones reales de acceso. Diseñarla bien exige ir más allá de roles generales y considerar permisos, scopes, ownership, tenants, propiedades sensibles y estado del negocio. Cuando esta capa se simplifica demasiado, la API puede estar correctamente autenticada pero profundamente expuesta.

En el próximo tema profundizaremos en dos fallas especialmente peligrosas: Broken Object Level Authorization y Broken Function Level Authorization, para ver cómo aparecen en la práctica y cómo prevenirlas.