VolundOS

VolundOS como provedor de identidade dos Apps

Os sistemas que os agentes publicam não têm cadastro próprio: quem entra usa a conta do VolundOS, que funciona como provedor de identidade OIDC.

Atualizado em 20 de agosto de 2026

VolundOS como provedor de identidade dos Apps

Camada funcional

Os sistemas que os agentes publicam não têm cadastro próprio: quem entra usa a conta do VolundOS. A plataforma é o provedor de identidade OIDC dos Apps — emite os tokens e diz quem é a pessoa e o que ela pode fazer.

Identidade do App como cliente

Cada App publicado é registrado como um cliente OIDC próprio, com seu próprio destino de retorno de login e sua própria credencial de acesso. Essa separação é o que impede que um App publicado seja usado para obter acesso a outro.

Há ainda um destino de login válido apenas enquanto o ambiente de desenvolvimento do App está ativo, para não deixar um endereço de teste valendo para sempre depois que o desenvolvimento parou.

Tempos de vida

TokenValidade
Acesso10 minutos
Identidade10 minutos
Renovação30 dias

Rotação de credencial sem derrubar o App

Trocar a credencial de acesso de um App já publicado, sem interromper quem está usando, exige uma janela em que a credencial antiga e a nova valem ao mesmo tempo. Sem essa janela, o App ficaria com a credencial rejeitada em pleno funcionamento; invertendo a ordem, o problema só mudaria de lugar. A troca é feita de forma que uma rotação em andamento nunca seja desfeita por engano por outro processo que ainda não viu a credencial nova.

Revogação: o que "trocar a credencial" não faz

Trocar a credencial de um App impede que quem a obteve de forma indevida consiga tokens novos — mas, por si só, não invalida os tokens que já estavam em circulação. Um procedimento de segurança que parasse na troca de credencial resolveria só metade do problema, e daria a falsa impressão de que o incidente foi contido por completo.

Por isso a revogação é uma ação própria, separada da troca de credencial: ela derruba as sessões ativas e invalida os códigos de login em andamento. O que nem a troca de credencial nem a revogação alcançam: um token de acesso já emitido continua valendo até expirar — no máximo dez minutos — porque ele é verificado sem precisar consultar a plataforma a cada uso. Essa é a folga deliberada para que a plataforma nunca se torne um ponto único de falha de todo App publicado.

Sair da organização bloqueia login novo e renovação

Sair da organização bloqueia login novo em qualquer App publicado por ela. A renovação de sessão também passou a checar esse vínculo a cada vez — sem essa checagem, uma pessoa desligada continuaria entrando nos Apps daquela organização por até 30 dias, que é o tempo de validade do token de renovação.

Isso não alcança um token de acesso já emitido: como a seção anterior explica, ele continua valendo até expirar — no máximo dez minutos.

Um agente também pode ser sujeito do token (13/08/2026)

Até aqui só uma pessoa entrava num App autenticada. Agora um agente do VolundOS também pode agir dentro de um App, sem senha nem credencial própria — a plataforma emite o token da mesma forma, como uma decisão interna, não como uma troca de credencial.

Dois modos, escolhidos por quem configura a conexão (nunca inferidos pela plataforma):

ModoQuem aparece como sujeito do tokenPermissões que valemA trilha registra
Delegadoa pessoaas da pessoa"Maria (via agente X)"
Próprioo agenteas concedidas ao agente"agente X"

Confundir os dois não dá erro — dá uma trilha de auditoria que mente sobre quem autorizou o quê. Por isso o modo vem sempre de uma configuração explícita e nunca é adivinhado pela presença ou ausência de um campo.

No modo próprio, o agente não tem baseline nenhum vindo de papel de organização (owner/admin não empresta poder a um agente) e não herda concessão de time — ele só pode o que foi concedido diretamente a ele. Um agente apagado, ou movido para fora da organização, perde o acesso na pergunta seguinte, sem que ninguém precise revogar nada — o mesmo efeito que sair da organização já tinha para uma pessoa.

Para um agente, a plataforma não emite ID token nem token de renovação: não há sessão de navegador para inaugurar, e quando o token de acesso expira (dez minutos), a plataforma simplesmente emite outro — mais simples e mais seguro do que guardar uma credencial de máquina de longa duração.

Como a conexão chega até aqui: um servidor MCP que aponta para o próprio App

[CORRIGIDO 16/08/2026] Até 15/08/2026, quando um agente registrava outro App do VolundOS como servidor de ferramentas (MCP), a conexão guardava essa escolha (App, modo, e no delegado a pessoa) num registro próprio do banco, fora de qualquer fluxo OAuth. Esse canal foi retirado do produto — ver a seção "Fim do canal próprio de conexão com App" mais abaixo. A conexão hoje segue o mesmo OAuth 2.1 padrão de qualquer servidor MCP remoto (descoberta, registro dinâmico, tela de consentimento com escolha de agente), com uma única diferença: quando a plataforma detecta que o destino é um App dela mesma, a tela de consentimento já abre com o agente dono da conexão marcado — a pessoa confirma em vez de procurá-lo de novo numa lista.

Cliente público, para MCP de fora (14/08/2026)

Até aqui, todo cliente OIDC de um App era confidencial — tinha segredo. Um cliente MCP que roda na máquina de quem usa (fora da plataforma) não tem onde guardar segredo nenhum, e o provedor passou a aceitar esse tipo de cliente: público, identificado só pelo próprio registro, sem credencial. A troca do código é protegida por PKCE, que prova que quem resgata o código é quem o pediu — não é autenticação do cliente, é proteção do código.

O tipo do cliente vem sempre do registro (nunca é inferido pela presença ou ausência de segredo) — inferir faria um App que simplesmente perdesse a credencial ser tratado como público, e a troca de código passaria sem erro nenhum. Um cliente público nunca tem segredo, nem janela de rotação; um confidencial sempre tem — as duas formas são mutuamente exclusivas por regra do banco.

A comunicação entre a plataforma e o App exige conexão segura (TLS) em toda etapa — autorização, emissão e revogação de token, e a conexão de MCP que um App faz de volta para outro. A única exceção é loopback local, sem interruptor para "isto não é produção".

Descoberta padrão para cliente de MCP (14/08/2026)

O provedor já publicava tudo em /.well-known/openid-configuration — o caminho padrão OIDC. Só que um cliente de MCP não pede esse caminho: a especificação de autorização do MCP manda pedir /.well-known/oauth-authorization-server (RFC 8414), um endereço diferente para o mesmo documento. Sem esse segundo endereço, conectar um App do VolundOS por um cliente de MCP genérico falhava na descoberta, e o erro ("não consegui descobrir o servidor de autorização OAuth") apontava para o lugar errado — quem lia ia conferir o App, não o provedor, que respondia normalmente no caminho antigo.

O provedor agora responde ao mesmo documento nos dois endereços — a mesma função monta os dois, para não haver risco de divergirem entre si com o tempo.

Do lado do App, produzido pelo modelo-base que toda aplicação usa, o mesmo avanço adiciona a contrapartida: a resposta de recusa por falta de autorização passa a indicar, no cabeçalho, onde pedir acesso (RFC 9728), e o App publica um endereço próprio, também padrão, dizendo qual é o seu Authorization Server. Nenhuma das duas mudanças altera o que já era verificado nem quem já tinha acesso — só ficou descobrível por um cliente que não conhece o VolundOS de antemão.

Cliente externo por organização (14/08/2026)

É o registro do cliente MCP de fora citado acima: cada organização pode cadastrar clientes externos que apontam para um App específico dela, com seus próprios destinos de retorno de login (até um limite por cliente) e um rótulo para reconhecê-lo numa lista. Hoje esse cadastro é feito por API — ainda não há tela própria para isso.

Revogar um cliente externo é, como para o App, dois atos: marcar como revogado (impede login novo) e derrubar as sessões que já circulam (o que já estava em andamento). Fazer só um dos dois deixa a outra metade do problema em aberto. A revogação é sempre escopada ao App-alvo daquele cliente — pedir a revogação a partir de outro App da mesma organização é recusado.

Um cliente de MCP se registra sozinho (15/08/2026, RFC 7591)

Até aqui, todo cliente que fala com o provedor precisava ser cadastrado por alguém (App do próprio VolundOS, ou cliente externo por organização, na seção anterior). Um cliente de MCP genérico (Claude Desktop, Cursor, VS Code) chega sem nada disso — nunca houve conversa prévia com a plataforma. /oauth/register aceita esse pedido de registro sem sessão nem conta: devolve um identificador de cliente público (sem segredo, protegido por PKCE) pronto para usar em /oauth/authorize.

O endpoint não pergunta, e não pode saber no registro, a qual App aquele cliente vai falar — essa resposta só chega no pedido de autorização seguinte, pelo resource (RFC 8707, próxima seção). Até lá, um cliente registrado aqui é recusado na tela de autorização com mensagem própria.

Duas contenções de abuso, porque o pedido é público e qualquer um pode chamar: um limite por endereço de origem (checado antes de ler o corpo do pedido) e um teto de registros por janela de tempo — a resposta de limite excedido leva Retry-After.

O resource amarra o cliente ao App, e a pessoa escolhe quem age (15/08/2026, RFC 8707 + RFC 8693)

Um cliente registrado dinamicamente (seção anterior) não tem App nenhum vinculado. Isso passa a ser resolvido a cada pedido de autorização pelo parâmetro resource, que a especificação de autorização do MCP já obriga o cliente a mandar: ele nomeia a URL canônica do endpoint MCP do App-alvo (<origem>/api/mcp), e a plataforma traduz essa origem para um App a partir da mesma lista de destinos de retorno de login já usada para autenticar aquele App — não uma tabela paralela, que divergiria no primeiro deploy que mudasse um alias. Esse vínculo viaja com o código de autorização e com o token de renovação; não é reconsultado a cada troca.

Na mesma tela, um cliente de fora (externo ou registrado dinamicamente) passa a perguntar quem age: a própria pessoa (o padrão) ou um agente dela, nomeado explicitamente. O agente escolhido vira o claim act do token (RFC 8693) e não amplia poder nenhum — as permissões continuam sendo as da pessoa. O login do próprio App (o caminho mais quente, usado hoje) não ganhou passo nenhum: só cliente externo ou dinâmico passa pela tela de consentimento. A escolha é sempre conferida contra a lista de agentes que aquela pessoa pode usar naquela organização — nunca aceita como veio do formulário.

Fim do canal próprio de conexão com App (15/08/2026)

O que a seção "Como a conexão chega até aqui", acima, descrevia até 15/08/2026 — um registro do banco guardando App, modo e pessoa fora de qualquer OAuth — foi removido do produto: o código que lia esse registro foi retirado e a coluna correspondente derrubada por migration, confirmadas as duas em produção. Motivo: esse canal cunhava token sem audiência negociada — a falha que as duas seções anteriores (resource e registro dinâmico) resolvem pelo caminho padrão — e nenhum cliente de MCP de fora sabia falar esse formato. A remoção do código e a da coluna saíram em dois PRs separados (expand/contract): o código só parou de nomear a coluna primeiro, e a coluna só caiu depois que esse código estava publicado — caso contrário, uma instância antiga da Vercel ainda lendo a coluna ficaria sem nenhum servidor de MCP, silenciosamente, no meio do rollout.

O App passa a conhecer a própria identidade de recurso (16/08/2026, contrato 6)

Até o contrato 5, o App só sabia se defender comparando o azp do token com o identificador do próprio cliente OIDC: só aceitava um token obtido pelo seu próprio cliente OIDC (o login web). A verificação de audiência (aud) existia, mas comparava dois campos do mesmo token entre si — nunca conseguia refutar nada, era circular.

Isso travava exatamente o cenário que a descoberta, o registro dinâmico e o vínculo por resource (seções acima) foram construídos para viabilizar: um cliente de MCP que se registra sozinho (RFC 7591) obtém um token válido, cujo azp é o dele — nunca o do App —, e o App recusava com 401.

O conserto: a plataforma passa a injetar uma quarta variável de ambiente no App, com a identidade do próprio agente App vinda de fora do token (não é segredo; é o mesmo identificador que já viajava dentro de um claim do token). Com ela, o App passa a exigir que a audiência do token aponte especificamente para o seu próprio identificador — um valor fixo seu, não mais derivado do próprio token — e o isolamento entre Apps passa a se apoiar de fato na audiência. O azp deixa de ser portão e vira só trilha de auditoria (qual cliente obteve o token).

Essa variável de ambiente é injetada pelos mesmos dois caminhos que já injetam o restante das variáveis de identidade do OIDC: o deploy e a reconciliação por turno no sandbox. Nenhum claim do token mudou — o contrato do scaffold subiu de 5 para 6 só porque esse número acompanha o artefato, e é essa igualdade que a trava de coordenação de contrato vigia.

Fora de escopo, por decisão do Levi Nóbrega: Apps publicados antes do contrato 6 não recebem o conserto automaticamente — o scaffold só é copiado na criação de um App, sem um caminho de atualização automática para instâncias já existentes. Ficam recusando cliente de MCP externo até serem recriados — tratado como nota de contexto, já que a funcionalidade ainda está em alpha.

Validado ao vivo em produção em 16/08/2026: uma chamada de ferramenta feita por um cliente de MCP externo/dinâmico passou a responder 200 onde antes respondia 401.

Verificação de superfície: o que o App diz vs. o que ele expõe (14/08/2026)

Um App declara a própria superfície a cada turno, mas declarar não é o mesmo que confirmar. A plataforma agora pode perguntar diretamente ao App publicado o que ele expõe de verdade e comparar com o que foi declarado — resolvendo uma lacuna registrada desde 11/08/2026.

A pergunta não usa a lista de ferramentas já filtrada por permissão (isso esconderia exatamente a deriva que se procura: uma ferramenta que exige uma chave inexistente no catálogo continuaria fora da lista dos dois lados). Em vez disso, o App expõe uma rota própria de introspecção não filtrada, com a chamada assinada por um segredo que as duas pontas já compartilham — o segredo em si nunca trafega, só a prova de posse, com validade de 5 minutos.

A comparação sai em três desfechos, porque significam coisas diferentes para quem audita:

DesfechoSignificado
cleano que foi declarado bate com o que o App expõe
partialbate no que foi possível conferir, mas uma parte (hoje, endpoints em certas versões do scaffold) não é introspectável — não confundir com "sem deriva"
drifthá diferença: algo declarado que não existe, algo exposto que não foi declarado, ou a mesma ferramenta com permissão/natureza diferente dos dois lados

Indisponibilidade nunca vira "sem deriva". Se o App não está publicado, está numa versão antiga que não tem essa rota, ou está fora do ar, o resultado é "não suportado" ou "inalcançável" — nunca o mesmo carimbo de um App que foi conferido e está limpo.

A verificação é disparada por uma pessoa (na aba de segurança do agente), nunca automaticamente durante o carregamento da tela — evitaria deixar a tela lenta quando o App está fora do ar.

Uma tela de login que diz em qual App a pessoa está entrando (19/08/2026)

Até aqui, /oauth/authorize sem sessão mandava para a tela de login da plataforma — "Entrar na plataforma", com painel de marketing sobre agentes autônomos, sem nenhuma menção ao App que trouxe a pessoa até ali. A página era estática e não tinha como saber, no servidor, qual aplicação a chamou.

Agora /oauth/authorize sem sessão vai para /auth/app: um cartão único que resolve o App no servidor a partir dos dados do pedido de autorização e mostra nome, avatar e endereço do App, vestido com a marca da organização dona (whitelabel assume a tela inteira; sem whitelabel, marca do VolundOS). A tela de consentimento que vem logo depois, para cliente de fora, recebeu o mesmo cabeçalho de identidade.

Nenhum valor não validado da query string chega a ser exibido. Uma tela que pede senha e imprime texto vindo da URL é um canvas de phishing pronto. O endereço mostrado só vem do pedido de autorização quando (a) o cliente é o do próprio App e (b) o destino está registrado para aquele App, por igualdade exata — senão cai para o endereço de publicação conhecido do App, e sem ele a linha simplesmente some. A condição (a) existe porque, num pedido de cliente MCP externo, o endereço de retorno é o 127.0.0.1 da máquina de quem usa — sem essa checagem a tela rotularia o App com o endereço de um terceiro.

Ainda nao existe cadastro proprio no App: o formulario de credenciais e o mesmo da plataforma (compartilhado), so o cabecalho de identidade muda — quem entra continua usando a conta do VolundOS, coerente com o resto deste documento.

Onde fazer isso

  • Rotacionar a credencial de acesso de um App: na aba de segurança do agente.
  • Configurar um agente para agir dentro de um App: ao cadastrar aquele App como servidor MCP do agente (conexão padrão OAuth 2.1; a tela de consentimento pergunta quem age — a pessoa ou um agente delegado — na primeira vez que a conexão precisa de autorização).

On this page