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
A pessoa entra na sua aplicação
A sua aplicação recebe um access token da pessoa, como sempre.
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.
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.O agente chama a API
O novo token tem a pessoa em
sub, o agente emacte a delegação emdelegation_id, então a sua API vê tanto para quem é a chamada quanto quem a está fazendo.
Configure uma delegação
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.
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:
Campo Regras Escopos Pelo menos um, entre os escopos que a aplicação pode pedir. É o teto: uma troca pode pedir menos, nunca mais. Encadeamento De 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. Prazo Opcional. No futuro e no máximo 365 dias à frente. Sem prazo, a delegação vale até ser retirada.
Escrita uma vez, nunca editada
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.
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:
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âmetro | Valor |
|---|---|
grant_type | urn:ietf:params:oauth:grant-type:token-exchange |
subject_token | O access token da pessoa, emitido pelo mesmo realm e ainda válido. |
subject_token_type | urn:ietf:params:oauth:token-type:access_token, o único tipo aceito. Um refresh token nunca pode ser trocado. |
requested_token_type | Opcional. Quando enviado, urn:ietf:params:oauth:token-type:access_token. |
scope | Opcional. Os escopos que o novo token deve trazer; sem ele, são pedidos os escopos do token de origem. |
resource | Opcional. 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
{
"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
}subcontinua sendo a pessoa;azpé o client que age.actnomeia 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_idnomeia 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_accesse nos outros mapas que um token de pessoa tem, mas nenhumclient_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ó emact,delegation_ideazp. - O token mantém o
sidda 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: falsena hora para todo token que traz odelegation_iddela. - Uma API que só valida tokens localmente continua aceitando os que já tem até eles expirarem. O
revocationLimitSecondsda resposta diz por quanto tempo, no máximo. - Uma retirada não pode ser desfeita, e retirar duas vezes é recusado.
Erros
Os erros seguem a RFC 6749: error e error_description, mais o error_code próprio do Authio.
| Erro | Código de erro | Por quê |
|---|---|---|
unauthorized_client | GrantTypeDisabled | O Token Exchange não está habilitado no client que age. |
invalid_request | DelegationNotPermitted | Não há delegação em vigor para este client e esta pessoa. |
invalid_request | DelegationDepthExceeded | O token de origem já tem mais atores do que a delegação permite. |
invalid_request | DelegationSubjectTokenInactive | O token de origem expirou, foi revogado, é de uma sessão encerrada ou não é deste realm. |
invalid_request | DelegationSubjectTokenTypeUnsupported | subject_token_type não é o tipo access token. |
invalid_scope | DelegationScopesExceedGrant | Os escopos pedidos excedem o token de origem ou a delegação. |
invalid_target | DelegationResourceExceedsGrant | resource 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.