Autorização por tenant#
A autorização por tenant permite que o banco de cada tenant seja a fonte de verdade para restringir o que um usuário pode fazer no Sulfite. O token continua dizendo o teto de permissões; a view
sulfite_authorized_users no banco do tenant aplica o recorte por usuário.
Quando usar#
Use este recurso quando:
- cada tenant já tem usuários, cargos ou permissões no próprio banco;
- o Sulfite deve refletir revogações imediatamente;
- você quer evitar emitir um novo token toda vez que a permissão de um usuário muda;
- um hub externo emite JWTs, mas a autorização fina fica nos bancos dos tenants.
Como funciona#
Em cada request autenticada, o servidor:
- resolve o tenant da request;
- encontra a primeira conexão
databasedesse tenant; - procura a view
sulfite_authorized_usersno schema configurado; - consulta a linha pelo email do token;
- aplica
tokenPermission && dbPermissionem cada permissão.
can_edit_global é uma exceção proposital: ele vem sempre do token e nunca da view, porque o banco do tenant não pode conceder acesso ao namespace global do operador.
Ativação#
O recurso fica disponível quando o sulfite_server recebe um ServerConnectionRegistry
e o tenant tem pelo menos uma conexão database.
Não há variável de ambiente específica para ligar a autorização por view. A ativação operacional é criar a view no banco do tenant:
CREATE VIEW sulfite_authorized_users AS
SELECT
email,
can_insert,
can_edit,
can_delete
FROM ...;
Se a conexão existe, mas a view ainda não foi criada, o Sulfite usa o fallback token-only. Isso permite migrar tenants gradualmente.
Contrato da view#
A view mínima deve expor estas colunas:
| Coluna | Tipo esperado | Obrigatória | Descrição |
|---|---|---|---|
email |
text |
Sim | Email usado para casar com o token |
can_insert |
boolean |
Sim | Permite POST /reports |
can_edit |
boolean |
Sim | Permite PUT /reports/:id |
can_delete |
boolean |
Sim | Permite DELETE /reports/:id |
Colunas opcionais também podem ser expostas:
| Coluna | Default quando ausente | Descrição |
|---|---|---|
can_list | true | Lista relatórios |
can_generate | true | Gera outputs |
can_settings |
false |
Gerencia conexões, tokens e introspecção |
can_share |
false |
Cria links de compartilhamento |
can_admin | false | Admin multi-tenant |
Colunas extras são ignoradas.
Schema da view#
O schema é resolvido nesta ordem:
extra.authSchemaextra.schemapublic
Exemplo com a view no schema padrão:
{
"name": "tenant-db",
"type": "database",
"host": "db.example.com",
"port": 5432,
"database": "tenant_acme",
"username": "reader",
"password": "secret",
"ssl": true,
"extra": { "schema": "public" }
}
Exemplo separando schema de dados e schema de autorização:
{
"name": "tenant-db",
"type": "database",
"host": "db.example.com",
"port": 5432,
"database": "tenant_acme",
"username": "reader",
"password": "secret",
"ssl": true,
"extra": {
"schema": "erp",
"authSchema": "sulfite_meta"
}
}
Nesse caso o Sulfite procura sulfite_meta.sulfite_authorized_users, enquanto os datasources podem continuar usando o schema
erp.
Exemplo de view#
CREATE VIEW public.sulfite_authorized_users AS
SELECT
u.email,
p.can_create_reports AS can_insert,
p.can_edit_reports AS can_edit,
p.can_delete_reports AS can_delete,
p.can_generate_reports AS can_generate,
p.can_manage_reports AS can_settings
FROM users u
JOIN roles r ON r.id = u.role_id
JOIN report_permissions p ON p.role_id = r.id
WHERE u.active = true;
Uma linha ausente significa usuário não autorizado:
| Situação | Resultado |
|---|---|
| View não existe | Fallback para permissões do token |
| View existe e email não aparece | Permissões negadas para o escopo da view |
Token não tem email e a view existe | Permissões negadas |
| Erro de conexão ou query | Request falha fechado com 503 |
authSchema inválido | Erro de configuração |
Tokens e email#
O lookup usa o campo email do token. Tokens emitidos pelo próprio Sulfite preenchem email
a partir do subject informado em POST /tokens.
Para JWT RS256 via JWKS, o IdP deve emitir a claim email:
{
"sub": "user-123",
"email": "ana@example.com",
"tenant_id": "tenant-acme",
"permissions": {
"reports": {
"list": true,
"generate": true,
"create": true,
"edit": true,
"delete": false
}
}
}
Se a claim email estiver ausente, o Sulfite só consegue usar token-only enquanto a view não existir. Quando a view está presente, o usuário não identificável é negado.
Interseção de permissões#
Exemplo:
| Permissão | Token | View | Resultado |
|---|---|---|---|
can_list |
true |
true |
true |
can_insert |
true |
false |
false |
can_edit |
false |
true |
false |
can_delete |
true |
true |
true |
can_edit_global |
true |
ignorado | true |
Isso permite um desenho simples:
- o token define o teto que o operador ou IdP aceita conceder;
- a view define o estado atual do usuário dentro do tenant;
- revogar ou alterar a linha na view afeta a próxima request.
Checklist#
- A conexão do tenant é do tipo
database. -
extra.authSchemaouextra.schemaaponta para o schema correto, ou a view está empublic. -
A view contém
email,can_insert,can_editecan_delete. - O token HMAC ou JWT externo contém
email. -
A role de banco usada pelo Sulfite consegue fazer
SELECTna view. - A view não expõe ou depende de
can_edit_global.
Páginas relacionadas#
- Autenticação & Tokens — emissão, refresh e permissões do token
- Conexões — configuração da conexão
database - Hub externo — JWT RS256 e registry remoto por tenant
- Multi-tenancy — isolamento lógico entre tenants