# Usuários e Acessos > A gestão de usuários e convites que todo App member-central já traz — permissões nativas, quem convida, convites pela Central, página própria e endpoints. Todo App `member-central` ou `root-central` nasce com a gestão de usuários do OonCore. Não há código a escrever para o caso padrão. ## O que vem por padrão - Página **`/usuarios-acessos`** (componente `CoreUsersAccess`) com o item **Usuários e Acessos** na seção **Configurações** do menu. - Para mudar onde o item aparece (outra seção, ordem ou o menu do usuário), declare na navegação do App um item com `href: "/usuarios-acessos"` e `permissions: ["users.read"]` — ele substitui o item padrão, e a página continua a do Core (0.7.39). Exemplo: `{ label: "Usuários e Acessos", href: "/usuarios-acessos", section: "Configurações", order: 60, permissions: ["users.read"], action: "user-menu" }`. - O perfil `admin` vê a página, convida, copia e regenera links, revoga convites e altera perfis. - Os demais perfis não veem a página até receberem as permissões abaixo. ## Permissões nativas | Permissão | O que libera | |---|---| | `users.read` | Ver a página e a lista de usuários e convites | | `users.invite` | Convidar, copiar o link, regenerar e revogar convites | | `users.update` | Alterar o perfil de um usuário (fluxo local) | | `users.disable` | Desativar ou reativar um usuário (fluxo local) | | `roles.read` | Listar os perfis do App | Já existem no Core: basta atribuí-las aos perfis — não declare em `rbac.permissions`. ## Quem pode convidar ```json { "rbac": { "roles": [ { "code": "admin", "name": "Administrador", "admin": true, "permissions": ["*"] }, { "code": "gestor", "name": "Gestor", "description": "Convida pessoas e acompanha os acessos da equipe.", "permissions": ["users.read", "users.invite", "pedidos.read"] }, { "code": "operator", "name": "Operador", "permissions": ["pedidos.read", "pedidos.write"] } ] } } ``` - **Sem escalada de privilégio:** quem convida só atribui perfis cujas permissões já possui (`RBAC_PRIVILEGE_ESCALATION_DENIED`). `"*"` só é atribuído por quem também tem `"*"`. - **Último administrador:** no fluxo local, o último admin ativo não pode ser rebaixado nem desativado. - **Clientes de App licenciado:** a autoridade comercial é decidida pela Central para aquela licença. ## Convites pela Central Por padrão os convites são **locais**: o App gera o link e quem convida o envia. Para a Central de Ativações gerir: ```json title="central.app.json" { "auth": { "invitations": "central" } } ``` - **E-mail** enviado pela Central com a identidade Oon e link para `/accept-invite` do App; `delivery` informa se saiu (`sent`) ou falhou (`failed` + `reasonCode`). - **Cadastro:** conta nova informa nome, CPF, telefone, senha e aceite dos termos; conta existente usa a senha ou a sessão aberta. - **Concessão:** vínculo com a organização e acesso ao App ficam na Central, com limite de usuários do plano e auditoria. Requer App publicado pela Plataforma (credencial de deployment e `PUBLIC_APP_URL` em HTTPS). No runtime local o fluxo permanece local. > [!WARNING] > Ao ligar, a primeira operação de gestão **revoga os convites locais pendentes**, com auditoria. Acessos ativos não mudam. Não volte para `local` para recuperar links antigos — emita convites novos. `OON_CENTRAL_INVITATIONS_ENABLED` (`true`/`false`) no runtime continua aceita apenas como chave de emergência. ## Página própria ```tsx title="frontend/src/app/app.tsx" export const app = defineOonApp({ // ... systemPages: { usersAccess: MinhaGestaoDeAcessos, // mesma rota e item de menu // ou usersAccess: false — remove a página e o item padrão }, }); ``` ```tsx import { Can, useOonApi } from "@oondemand/oon-core-front"; export function MinhaGestaoDeAcessos() { const { http } = useOonApi(); async function convidar(email: string, roleCode: string) { const { data } = await http.post("/core/users/invitations", { email, roleCode }, { headers: { "idempotency-key": crypto.randomUUID() }, // reutilize a mesma chave ao repetir a tentativa }); return data; // { invitation, access, inviteUrl?, delivery? } } return {/* formulário de convite */}; } ``` A página não deve guardar tokens nem montar links: o link vem sempre do backend. ## Endpoints | Método e rota | Permissão | Uso | |---|---|---| | `GET /core/role-catalog` | pública | Catálogo de perfis | | `GET /core/rbac` | pública | Política resumida | | `GET /core/roles` | `roles.read` | Perfis completos | | `GET /core/users` | `users.read` | Usuários e convites pendentes | | `POST /core/users/invitations` | `users.invite` | `{ email, roleCode, name? }` + `idempotency-key` | | `GET /core/users/invitations/:id/link` | `users.invite` | Recupera o link | | `POST /core/users/invitations/:id/regenerate` | `users.invite` | `{ version }` — invalida o anterior | | `DELETE /core/users/invitations/:id` | `users.invite` | `{ version }` — revoga | | `PATCH /core/users/:id` | `users.update` / `users.disable` | `{ roleCode }` ou `{ status }` (fluxo local) | | `POST /core/invitations/inspect` | pública | `{ token }` | | `POST /core/invitations/accept` | pública | `{ token, intent, password?, registration?, version? }` | `inviteUrl` aponta para `PUBLIC_APP_URL/accept-invite#token=…` — o token vai no **fragmento**, que não chega a logs nem a servidores intermediários. ## Aceite `/accept-invite` é uma página pública do Core que trata conta nova, conta existente e sessão já aberta, com mensagens legíveis e "Código · Protocolo · Central" em caso de erro. Uma página própria de aceite não é necessária nem recomendada. Fonte: https://sdk.oonapps.com/docs/seguranca/usuarios-e-acessos