Un sistema de autenticación parece pedir a gritos una base de datos relacional. Usuarios, roles, sesiones, concesiones OAuth, refresh tokens, todo referenciado entre sí. El nuestro no usa ninguna. Corre sobre Azure Table Storage, un almacén que te da una partition key, una row key y casi nada más. Sin joins, sin secondary indexes que sirvan de algo, sin operador de incremento, sin transacciones multifila con la forma a la que estás acostumbrado. Fue una decisión. Esto es lo que compra esa decisión, los patrones que la hacen funcionar y la parte en la que SQL habría sido realmente más fácil.

La razón para hacerlo es el coste y la simplicidad operativa. Sin connection pool que agotar, sin instancia de base de datos que dimensionar, parchear o conmutar por error, con escalado por partición que obtienes gratis. Mantener una tabla no cuesta casi nada y no hay nada que se pueda agotar. El precio de eso es un almacén sin query planner, que solo rinde cuando tus patrones de acceso son tan predecibles como tonto es el almacén. Los de la autenticación lo son, así que todo el diseño se apoya en ello.

La clave hace el trabajo que haría un diseño de tabla. Sin joins, diseñas la clave para que la consulta sea la clave. Desnormalizas a propósito, eliges las particiones para que tus lecturas calientes sean point-gets, y codificas identidades compuestas directamente en la row key, por ejemplo "{pk}|{rk}" para entradas que necesitan una identidad compuesta en un almacén que ofrece un solo hueco de row key. La pregunta "cómo busco esto" hay que responderla al diseñar la clave, no en tiempo de consulta. Para la autenticación eso está bien, porque los patrones de acceso son conocidos y no cambian con el tiempo: obtener un usuario por id, obtener las concesiones de un usuario, consumir un código. No estás explorando los datos. Conoces cada pregunta de antemano.