Máquina a máquina
Deixe um serviço chamar as suas APIs como ele mesmo com o grant client credentials: clients e consumers, escopos e audiência, cache de tokens e rotação de credenciais.
Quando não há pessoa envolvida — um job noturno, um backend chamando outro, a integração de um parceiro —, quem chama se autentica como ele mesmo com o grant client_credentials (RFC 6749). Ele apresenta um client ID e um segredo no endpoint de token e recebe um access token que descreve o serviço, não um usuário.
Configure o client
Crie um client confidencial
Em Clients, crie um client com a autenticação de client ligada e habilite o grant
client_credentials. Um client público não pode usá-lo: ele não tem segredo para apresentar. Copie o segredo quando ele aparecer — ele aparece uma única vez.Dê a ele os escopos de que o serviço precisa
Libere os escopos no client, ou num consumer, se cada integração deve ter credencial e permissões próprias.
Deixe-o alcançar a API
Registre a API como servidor de recurso, por exemplo
https://api.example.com, e acrescente o client aos clients permitidos dele. Os tokens pedidos comresourcepassam a levar esse identificador emaud.
Consumers: uma credencial por integração
Um consumer é uma credencial extra presa a um client, com escopos e papéis próprios. Dê a cada sistema que chama você um consumer próprio e você consegue ver, limitar e revogar cada um sem mexer nos outros. Crie-os em Consumers: escolha o client, o tipo Client Secret, um valor de 8 a 512 caracteres (ou gere um) e os escopos e papéis. O valor aparece uma vez, quando o consumer é criado ou o valor é trocado; depois só os quatro últimos caracteres aparecem, e uma edição que deixa o valor em branco o mantém.
| Aspecto | Segredo do client | Consumer |
|---|---|---|
| Enviado como | client_id e o segredo do client. | client_id do client e o valor do consumer como segredo. |
| Escopos | Os escopos do client. | Só os escopos do consumer; nada é herdado do client. |
| Papéis | Nenhum. | Os papéis do consumer, na claim consumer_resource_access. |
| Identificado no token por | azp. | azp, mais consumer_name, credential_id e credential_type. |
| Desligado ao | Desativar o client, o que para todas as integrações. | Desativar ou suspender só aquele consumer. |
A credencial de um consumer só vale para o client a que pertence, é apresentada com o método de autenticação registrado no client e precisa estar ativa. Quantos consumers você pode manter ativos depende do seu plano.
Tipos de consumer
| Tipo | Apresentado como | Validado por |
|---|---|---|
| Client Secret | O segredo do client, com o client_id do client, no token endpoint. | O Authio, que emite um token de client_credentials para o consumer. |
| Personal Access Token | client_secret do grant personal_access_token, com o client_id do client. | O Authio, que emite um token com sub = o consumer e azp = o client_id do client. |
| API Key | Como está, para a sua própria API (por exemplo num cabeçalho x-api-key que você define). | A sua API, no endpoint de introspecção do realm — veja Chaves de API. |
O tipo é definido na criação do consumer: uma atualização sem type o mantém, e uma que pede outro tipo é recusada com ValidationFailed em type. Para outro tipo, crie outro consumer. Cada autenticação de consumer — um token emitido ou recusado, uma chave aceita ou recusada — é um registro no log de acesso com o consumer e o client, e um webhook login_succeeded ou login_failed com consumer_id e consumer_name.
Chaves de API
Um consumer API Key é uma chave que o parceiro envia à sua API em cada chamada, sem trocar por token. A sua API confere a chave no endpoint de introspecção do realm (RFC 7662), autenticada como o client a que o consumer pertence — ou como o client com que o seu resource server faz introspecção, quando é o mesmo client — com token_type_hint=api_key. A chave nunca é validada pela API administrativa, e a API administrativa não a aceita.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/introspect \
-u "acme-orders-api:$CLIENT_SECRET" \
-d token="$PARTNER_API_KEY" \
-d token_type_hint=api_keysubecredential_idsão o consumer;client_idé o client;scopetraz todos os escopos permitidos ao consumer (inclusive os opcionais, já que uma chave não tem como pedi-los), sem os escopos de pessoa.- Uma chave errada, de outro client, ou de um consumer inativo ou suspenso responde
{"active": false}. Não háexp: a chave vale até o consumer ser desligado ou ter o valor trocado, então faça a introspecção em cada chamada ou guarde a resposta por poucos segundos. - Sem
token_type_hint=api_keyum valor só é verificado como token, então uma API que espera tokens nunca recebe uma chave como se fosse um. Com o hint, um valor que não é chave ainda é verificado como token, como pede a RFC 7662.
Peça um token
curl -X POST https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/token \
-u 'acme-reports:YOUR_CLIENT_SECRET' \
-d grant_type=client_credentials \
-d scope=orders:read \
--data-urlencode resource=https://api.example.com-u envia a credencial por HTTP Basic (client_secret_basic, o padrão). Se o client estiver registrado com client_secret_post, mande client_id e client_secret como campos do formulário: o Authio só aceita o método registrado. Não há refresh token nem ID token — não existe sessão para manter.
Quais escopos e qual audiência você recebe
- Os escopos padrão da credencial são sempre concedidos; os opcionais, só quando
scopeos cita. - Um escopo pedido que a credencial não tem fica fora do token, sem recusa — confira
scopena resposta. - Escopos de pessoas —
openid,profile,email,phone,address,offline_access— nunca entram num token de máquina. - Com
resource,audé aquele servidor de recurso e os escopos do servidor que você pedir são acrescentados. Um recurso que o client não pode alcançar é recusado cominvalid_target. - Sem
resource,audé a audiência do client —Authiopor padrão —, que a sua API não deve aceitar.
O sub do token é o ID interno do client e azp é o client ID, então uma API pode admitir um único client de máquina por azp — o RequireAuthioClient faz isso no .NET.
Guarde os tokens em cache
Não peça um token por chamada. Guarde-o até pouco antes de expires_in acabar e então peça outro: cada emissão é uma ida ao Authio, fica no log de acesso e conta como uso de client credentials. Guarde um token por combinação de escopos e recurso.
using Authio.Client.Extensions;
builder.Services.AddAuthioClient(builder.Configuration.GetSection("Authio"));
builder.Services
.AddHttpClient<OrdersApi>(client => client.BaseAddress = new Uri("https://api.example.com"))
.AddAuthioClientCredentials(options =>
{
options.Scopes = ["orders:read"];
options.Resource = "https://api.example.com";
});No .NET, o AddAuthioClientCredentials faz tudo isso: o token fica em cache por escopos e recurso, é renovado TokenRefreshSkew (um minuto) antes de expirar, é compartilhado entre chamadas simultâneas e é buscado de novo uma vez se a API responder 401. A configuração completa está em .NET.
Gire as credenciais
Gire o segredo de um client pela tela do client em Clients, e uma credencial da conta — uma chave de API, um token de acesso pessoal ou um client secret da conta — pela tela dela em Segredos de API. O novo valor aparece uma única vez. A rotação pergunta por que você está girando, e a resposta decide o que acontece com o valor substituído:
| Você escolhe | O valor anterior | Tokens emitidos com ele |
|---|---|---|
| Rotação de rotina, sem sobreposição | Recusado já na próxima chamada. | Continuam valendo até expirar. |
| Rotação de rotina, mantido por 15 minutos, uma hora ou um dia | Continua aceito até o fim do período e depois é recusado. O console só oferece os períodos que o ambiente permite. | Continuam valendo até expirar. |
| O valor atual vazou | Recusado já na próxima chamada. | Os access tokens emitidos antes da rotação ficam inativos na introspecção e são recusados pelas APIs do próprio Authio, e os refresh tokens deles param de funcionar. No segredo de um client, quem está conectado ao client precisa entrar de novo. |
- Sem indisponibilidade. Escolha uma sobreposição e publique o novo segredo em todas as instâncias enquanto o antigo ainda funciona; a tela do client diz até quando. Ou use consumers: crie um consumer novo com os mesmos escopos e papéis, publique o serviço com o valor dele e depois desative o consumer antigo.
- Depois de um vazamento. Escolha O valor atual vazou: nenhuma sobreposição é oferecida, porque um valor vazado precisa parar na hora.
- Corte também os tokens emitidos. Ligue Revoke Issued Tokens Immediately nas configurações de segurança do client. A introspecção passa a responder
active: falsepara um token cuja credencial foi desativada, revogada, expirou ou foi apagada — APIs que só conferem assinaturas localmente não percebem, então precisam da introspecção.
Solução de problemas
| O que aparece | Por quê | O que fazer |
|---|---|---|
401 invalid_client | Segredo errado, consumer inativo ou segredo enviado por um método diferente do registrado. | Confira o valor e use Basic ou campos de formulário, conforme o client está registrado. |
unauthorized_client | O grant client_credentials não está habilitado no client. | Habilite-o nos grants do client. |
invalid_target | O recurso não é um servidor de recurso que o client pode alcançar. | Confira o identificador e acrescente o client aos clients permitidos do servidor de recurso. |
| O token não tem um escopo que você pediu | A credencial não tem esse escopo, então ele ficou de fora. | Libere o escopo no client ou no consumer. |
| A API recusa a audiência do token | O token foi pedido sem resource. | Mande resource com o identificador da API. |