Pular para o conteúdo

Delegação e token exchange

Deixe um agente ou serviço agir em nome de uma pessoa com um token mais restrito, sob uma delegação que você retira quando quiser — OAuth 2.0 Token Exchange (RFC 8693).

Às vezes uma aplicação precisa chamar uma API como outra pessoa: um agente de IA trabalhando nos documentos de alguém, um serviço de back-end continuando uma requisição que o front-end recebeu. O Authio atende isso com o OAuth 2.0 Token Exchange (RFC 8693): o client que age apresenta o access token da pessoa e recebe um novo, emitido para ele, que mantém a pessoa como sujeito e nomeia o client como ator.

A troca só funciona quando uma delegação a permite: um registro escrito de que esta aplicação pode agir por esta pessoa, dentro destes escopos, por este tempo. Administradores escrevem delegações no console ou pela API administrativa, e podem retirá-las a qualquer momento.

Como funciona

  1. A pessoa entra na sua aplicação

    A sua aplicação recebe um access token da pessoa, como sempre.

  2. O agente recebe o token da pessoa

    A sua aplicação entrega o access token ao agente — um client do mesmo realm — junto com a tarefa que ele recebeu.

  3. O agente faz a troca

    Ele chama o endpoint de token com as próprias credenciais e o token da pessoa como subject_token. O Authio confere se o token ainda vale, encontra uma delegação em vigor para este client e esta pessoa que cubra os escopos pedidos e emite um novo access token.

  4. O agente chama a API

    O novo token tem a pessoa em sub, o agente em act e a delegação em delegation_id, então a sua API vê tanto para quem é a chamada quanto quem a está fazendo.

Configure uma delegação

  1. Habilite o Token Exchange no client que age

    Abra o client do agente em Clients e habilite o grant Token Exchange na aba Avançado. Habilite nele só os escopos de que o agente precisa: uma delegação só pode oferecer escopos que o client pode pedir.

  2. Escreva a delegação

    Abra Delegações, escolha Nova delegação, selecione o realm, a aplicação que vai agir e a pessoa por quem ela age, e defina os limites:

    CampoRegras
    EscoposPelo menos um, entre os escopos que a aplicação pode pedir. É o teto: uma troca pode pedir menos, nunca mais.
    EncadeamentoDe 0 a 3: quantos atores já podem estar no token que esta aplicação troca. 0, a escolha segura, quer dizer que ela só troca o token da própria pessoa.
    PrazoOpcional. No futuro e no máximo 365 dias à frente. Sem prazo, a delegação vale até ser retirada.

Escrita uma vez, nunca editada

Para mudar uma delegação, retire-a e escreva outra. As duas ficam no registro, e uma revisão de acessos posterior consegue ler o que foi permitido e quem encerrou.

A API administrativa aceita os mesmos campos e mais dois que o formulário do console não mostra: allowedResources, os servidores de recurso aos quais os tokens delegados podem ser endereçados, e organizationId, que restringe a delegação a uma organização de que a pessoa faz parte. Ela exige escrita no realm; veja API administrativa.

Criar uma delegaçãoBash
curl -X POST https://authio.api.hyperio.tech/api/v1/admin/realms/acme/delegation-grants \
  -H "Authorization: Bearer $AUTHIO_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "acme-agent",
    "subjectUserId": "6f1c2e7a-4b8d-4f0e-9a51-3c2d7e8b9f10",
    "scopes": ["documents:read"],
    "maxDepth": 0,
    "allowedResources": ["https://api.acme.com"],
    "expiresAt": "2026-12-31T23:59:59Z"
  }'

Troque um token

O client que age chama o endpoint de token do realm, autenticado com as próprias credenciais no método registrado para ele:

RequisiçãoBash
curl -X POST https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/token \
  -u "acme-agent:YOUR_CLIENT_SECRET" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
  -d "subject_token=$USER_ACCESS_TOKEN" \
  -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "scope=documents:read" \
  -d "resource=https://api.acme.com"
ParâmetroValor
grant_typeurn:ietf:params:oauth:grant-type:token-exchange
subject_tokenO access token da pessoa, emitido pelo mesmo realm e ainda válido.
subject_token_typeurn:ietf:params:oauth:token-type:access_token, o único tipo aceito. Um refresh token nunca pode ser trocado.
requested_token_typeOpcional. Quando enviado, urn:ietf:params:oauth:token-type:access_token.
scopeOpcional. Os escopos que o novo token deve trazer; sem ele, são pedidos os escopos do token de origem.
resourceOpcional. A API para a qual o novo token vai. Precisa estar entre os recursos da delegação, quando ela lista algum, e ser um servidor de recurso para o qual o client que age pode pedir tokens.

O Authio então confere que:

  • O token de origem ainda vale — assinatura, validade, revogação e sessão são conferidas por introspecção. Toda recusa sobre ele tem a mesma resposta, qualquer que seja o motivo.
  • Os escopos pedidos estão dentro dos escopos do token de origem e cabem inteiros em uma delegação em vigor para este client e esta pessoa. Delegações nunca se somam, e um pedido a mais é recusado nomeando o excesso — nunca recortado em silêncio.
  • O número de atores que já estão no token de origem está dentro do limite de encadeamento da delegação.
  • A pessoa ainda é membro da organização, quando a delegação é restrita a uma.

O token delegado

Payload do access tokenJSON
{
  "iss": "https://authio.api.hyperio.tech/realms/acme",
  "sub": "6f1c2e7a-4b8d-4f0e-9a51-3c2d7e8b9f10",
  "aud": "https://api.acme.com",
  "azp": "acme-agent",
  "scope": "documents:read",
  "sid": "0b7e4c2a-9d1f-4a6e-8c3b-5f2d1e9a7c40",
  "act": { "client_id": "acme-agent" },
  "delegation_id": "3f1d9b6e-0c4a-4f7d-b2e8-5a9c1d7e3b40",
  "exp": 1791372600
}
  • sub continua sendo a pessoa; azp é o client que age.
  • act nomeia o ator, no formato que a RFC 8693 descreve. Quando um token delegado é trocado de novo, o novo ator envolve o anterior: {"client_id": "acme-summarizer", "act": {"client_id": "acme-agent"}}. Cada aplicação de uma cadeia precisa de uma delegação própria para a pessoa.
  • delegation_id nomeia a delegação sob a qual este token foi emitido.
  • Ele carrega o acesso da pessoa e nada do próprio cliente que age: os papéis que a pessoa tem, diretamente ou por um grupo (inclusive os exclusivos do cliente que age), em realm_resource_access e nos outros mapas que um token de pessoa tem, mas nenhum client_resource_access, o mapa dos papéis concedidos ao próprio cliente. Uma API que lê papéis de um token delegado vê o que a pessoa pode fazer, nunca o que o agente pode fazer por conta própria; o agente aparece só em act, delegation_id e azp.
  • O token mantém o sid da pessoa, então encerrar a sessão dela também encerra os tokens delegados para as APIs que fazem introspecção.
  • Ele expira no máximo junto com a delegação, e nenhum refresh token é emitido.

Retire uma delegação

Abra a delegação em Delegações, escolha Retirar e diga por quê. O motivo é obrigatório e fica guardado com quem retirou e quando. Pela API administrativa, envie POST /api/v1/admin/realms/acme/delegation-grants/{grantId}/withdraw com um reason no corpo.

  • Nada mais é emitido sob ela, e nenhum token emitido sob ela pode ser trocado de novo.
  • A introspecção responde active: false na hora para todo token que traz o delegation_id dela.
  • Uma API que só valida tokens localmente continua aceitando os que já tem até eles expirarem. O revocationLimitSeconds da resposta diz por quanto tempo, no máximo.
  • Uma retirada não pode ser desfeita, e retirar duas vezes é recusado.
APIs que aceitam tokens delegados devem fazer introspecção — veja Servidores de recurso — ou manter curta a duração do access token, para que uma retirada valha na hora.

Erros

Os erros seguem a RFC 6749: error e error_description, mais o error_code próprio do Authio.

ErroCódigo de erroPor quê
unauthorized_clientGrantTypeDisabledO Token Exchange não está habilitado no client que age.
invalid_requestDelegationNotPermittedNão há delegação em vigor para este client e esta pessoa.
invalid_requestDelegationDepthExceededO token de origem já tem mais atores do que a delegação permite.
invalid_requestDelegationSubjectTokenInactiveO token de origem expirou, foi revogado, é de uma sessão encerrada ou não é deste realm.
invalid_requestDelegationSubjectTokenTypeUnsupportedsubject_token_type não é o tipo access token.
invalid_scopeDelegationScopesExceedGrantOs escopos pedidos excedem o token de origem ou a delegação.
invalid_targetDelegationResourceExceedsGrantresource está fora dos recursos que a delegação lista.

O token exchange tem um segundo uso: um servidor de recurso pode trocar o token que recebeu pelo access token de uma conta que a pessoa conectou, como a do GitHub. Veja Contas conectadas.

Próximos passos

Cookies de analytics

Gostaríamos de medir como o console é usado, com o Google Analytics, para enxergar em quais telas as pessoas travam. Isso grava um cookie que reconhece este navegador na sua próxima visita.

Recusar não muda mais nada. Os cookies que mantêm você conectado e lembram o seu idioma e o seu tema são necessários para o console funcionar, e ficam de qualquer forma. Ler a Política de Privacidade