Cómo construir un sistema de roles sobre servant-auth en Haskell

Fuentes: Servant Auth Roles

Este artículo describe el diseño e implementación de una librería que añade un sistema de roles y permisos sobre servant-auth, el mecanismo de autenticación de Servant, un framework para construir APIs en Haskell. El objetivo es permitir definir manejadores (handlers) distintos según el rol del usuario, manteniendo la compatibilidad con el combinador AuthProtect.

El diseño parte de una interfaz imaginaria: los roles se modelan como un tipo suma y se describen mediante una typeclass con un predicado CheckRole, que admite comprobaciones jerárquicas, por igualdad o por pertenencia a un conjunto. A partir de ahí se construye el combinador RequireRole, cuyo propósito es asociar un rol a cada ruta de la API y forzar una comprobación antes de ejecutar el manejador. Si el rol del usuario no cumple la condición, la ruta falla y Servant prueba la siguiente coincidencia, lo que produce un comportamiento de fall-through.

La pieza central es la instancia HasServer de RequireRole, donde se obtiene el AuthServerData del AuthHandler, se compara el rol mediante checkRole y se devuelve un error 403 en caso negativo. Para distinguir un fallo de autenticación de uno de autorización se usan delayedFail y delayedFailFatal, lo que permite tanto rechazar todas las peticiones no autenticadas como definir rutas de respaldo anónimas.

El autor va un paso más allá y propone un mecanismo de Proof tokens generado durante la comprobación de rol, capaz de restringir qué subrutinas puede invocar cada manejador según el rol verificado. Para vincular la prueba al sujeto concreto y no a un usuario arbitrario, el texto introduce técnicas de hasochism y singletons, elevando el UserRole de valor a índice del tipo. La versión final de la librería servant-auth-roles utiliza Template Haskell para ocultar el ruido boilerplate asociado.