Curupira, nosso Identity Provider em Rust

Curupira Identity Provider em Rust: IdP multi-tenant com PKCE obrigatório, chaves RSA por aplicação e segurança pronta para produção.

Avatar de Gabriel
Gabriel
Curupira, nosso Identity Provider em Rust

Todo mundo que já integrou login "na mão" sabe onde dói: OAuth2 mal configurado, tokens que vazam, e um IdP de terceiros que cobra por assento ou some com uma feature no próximo release. Cansamos disso e construímos o Curupira.

Imagem de capa/abertura que transmita um guardião de identidade digital robusto e confiável, evocando o folclórico Curupira como protetor.
Imagem de capa/abertura que transmita um guardião de identidade digital robusto e confiável, evocando o folclórico Curupira como protetor.

Por que diabos construir o próprio IdP

Autenticação é daquelas coisas que ninguém quer reinventar até precisar. Nosso caso era multi-tenant: várias aplicações, cada uma com seus usuários, papéis e regras. As opções prontas ou eram caras por assento, ou nos prendiam a decisões que não controlávamos. Construir o próprio IdP é assumir uma responsabilidade séria, mas nos deu o que faltava: controle total sobre chaves, tokens e política de segurança. O Curupira é um Identity Provider OAuth2 + OpenID Connect, pronto para produção, com issuer padrão em auth.dwcorp.com.br e licença MIT.

Rust não foi escolha de hype

Escrever um IdP em Rust parece exibicionismo até você lembrar o que um IdP faz: manipula segredos, valida tokens e roda no caminho crítico de toda requisição autenticada. Aqui a garantia de memória e a ausência de surpresas em runtime pagam a conta. A stack é Rust + Cargo, com PostgreSQL via SQLx — o que significa queries checadas em tempo de compilação e migrations versionadas. Se a query quebra, quebra no build, não às três da manhã em produção.

PKCE obrigatório e zero atalhos de segurança

A escolha que mais define o Curupira: PKCE é obrigatório. Não é opcional, não tem flag para desligar. Fluxo Authorization Code com PKCE S256 (RFC 7636) para todo mundo, cliente público ou não. Somamos a isso senhas com Argon2id, proteção CSRF, e endpoints de token e introspecção protegidos por API key. O projeto segue a RFC 9700, a BCP de segurança de OAuth2 — ou seja, as boas práticas atuais, não o que era aceitável em 2015. A ideia é simples: tornar o caminho seguro o único caminho.

Multi-tenant de verdade: uma chave RSA por aplicação

Multi-tenant costuma ser um adjetivo de marketing. No Curupira é arquitetura: cada aplicação tem seu próprio par de chaves RSA. Os JWTs são assinados em RS256, com rotação de chaves. Isso significa que comprometer ou rotacionar a chave de uma aplicação não contamina as outras. Em cima disso roda um RBAC com papéis específicos por aplicação e grupos de papéis, para você modelar permissões sem transformar cada tenant num caso especial. Discovery OIDC, ID tokens, UserInfo, introspecção e logout estão todos ali.

Compatível com FusionAuth, com log em três camadas

Uma decisão pragmática: o Curupira foi desenhado para ser compatível com o FusionAuth. Isso reduz atrito para quem já vem desse mundo e nos dá um vocabulário conhecido em vez de inventar o nosso. Observabilidade também não ficou de fora — são três camadas de log: tentativas de login, event logs e audit logs. Quando algo dá errado numa autenticação, dá para reconstruir o que aconteceu. E, a partir da v0.8, há um dashboard administrativo feito em Nuxt.js (Vue) com @nuxt/ui, porque gerenciar tenant e chave no grito de comando cansa rápido.

O que já roda e o que ainda vem

Sejamos honestos: o Curupira é um produto em evolução. As fases 0 e 1 — infraestrutura e gestão de tenants — estão prontas. As fases 2 a 5 estão no mapa: gestão de aplicações, usuários e papéis, logging e monitoramento, MFA, verificação de e-mail e webhooks. É um roadmap por fases justamente porque preferimos entregar cada camada bem-feita a empurrar tudo de uma vez e rezar.

Autenticação é chata quando funciona e catastrófica quando não. Construir o Curupira foi apostar que valia a pena ter esse pedaço crítico sob nosso controle — em Rust, com PKCE obrigatório e uma chave por tenant. Até agora, a aposta está de pé.

Gostou do artigo?

Compartilhe com seus amigos e ajude a espalhar conhecimento!