Exemplo de implementação (novo)
Esta página documenta exemplos para a nova versão da autorização entre sistemas do Acesso Cidadão.
Para integrações legadas, mantenha a documentação antiga baseada em
https://acessocidadao.es.gov.br/is/....
Visão geral
Na nova versão, tokens de sistema devem ser obtidos a partir do provedor publicado em:
https://token.acessocidadao.es.gov.br/.well-known/openid-configuration
O endpoint de token é:
https://token.acessocidadao.es.gov.br/connect/token
Os exemplos abaixo usam .NET moderno e mostram:
- como obter um token com
client_credentials; - como chamar uma API protegida;
- como validar corretamente o token na API consumida.
1. Obtendo um token de sistema
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
public sealed class TokenResponse
{
public string AccessToken { get; set; } = string.Empty;
public string TokenType { get; set; } = string.Empty;
public int ExpiresIn { get; set; }
}
public static class AcessoCidadaoTokenClient
{
private const string TokenEndpoint = "https://token.acessocidadao.es.gov.br/connect/token";
public static async Task<TokenResponse> GerarTokenAsync(
HttpClient httpClient,
string clientId,
string clientSecret,
string scopes,
CancellationToken cancellationToken = default)
{
var basicCredential = Convert.ToBase64String(
Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));
using var request = new HttpRequestMessage(HttpMethod.Post, TokenEndpoint)
{
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["scope"] = scopes
})
};
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", basicCredential);
using var response = await httpClient.SendAsync(request, cancellationToken);
var content = await response.Content.ReadAsStringAsync(cancellationToken);
if (!response.IsSuccessStatusCode)
{
throw new InvalidOperationException($"Erro ao obter token: {(int)response.StatusCode} - {content}");
}
var result = JsonSerializer.Deserialize<TokenResponse>(content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
if (result is null || string.IsNullOrWhiteSpace(result.AccessToken))
{
throw new InvalidOperationException("Resposta de token inválida.");
}
return result;
}
}
Exemplo de uso
var httpClient = new HttpClient();
var token = await AcessoCidadaoTokenClient.GerarTokenAsync(
httpClient,
clientId: "seu-client-id",
clientSecret: "seu-client-secret",
scopes: "api.read api.write");
Console.WriteLine(token.AccessToken);
2. Chamando uma API protegida
using System.Net.Http.Headers;
var apiClient = new HttpClient();
apiClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.AccessToken);
using var response = await apiClient.GetAsync("https://minha-api.exemplo.es.gov.br/recurso");
var responseBody = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new InvalidOperationException($"Erro na chamada da API: {(int)response.StatusCode} - {responseBody}");
}
Console.WriteLine(responseBody);
3. Validando o token na API ASP.NET Core
Configuração básica
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://token.acessocidadao.es.gov.br";
options.RequireHttpsMetadata = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://token.acessocidadao.es.gov.br",
ValidateAudience = true,
ValidAudience = "api-id-da-sua-api",
ValidateLifetime = true,
ValidateIssuerSigningKey = true
};
});
builder.Services.AddAuthorization();
Pipeline
app.UseAuthentication();
app.UseAuthorization();
4. Validando scopes na operação
Além da autenticação do JWT, cada endpoint deve validar os scopes exigidos pela operação.
Exemplo simples:
app.MapGet("/recurso", (ClaimsPrincipal user) =>
{
var scopes = user.FindAll("scope").Select(x => x.Value).ToArray();
if (!scopes.Contains("api.read"))
{
return Results.Forbid();
}
return Results.Ok(new { mensagem = "Acesso autorizado." });
})
.RequireAuthorization();
Dependendo da serialização do token, os scopes podem chegar em uma claim única separada por espaço. Ajuste a leitura conforme o padrão recebido pela sua aplicação.
5. O ponto mais importante na nova versão
Na nova versão, não use mais prefixo de scope como única forma de segregação entre APIs.
A API protegida deve validar sempre:
- assinatura;
- expiração;
issuer;aud;- scopes exigidos pela operação.
Exemplo do que não fazer
// Evite esse tipo de regra como barreira principal de segurança:
var permitido = scopes.Any(scope => scope.StartsWith("sistema-x."));
Exemplo do que fazer
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudience = "api-id-da-sua-api"
};
6. Recomendações práticas
- Use
HttpClientreutilizável. - Não faça cache de token além do tempo de expiração.
- Nunca exponha
client_secretem frontend. - Não aceite token emitido para outra API.
- Em caso de erro
401ou403, verifique primeiro:- se o
audesperado está correto; - se os scopes concedidos à aplicação estão corretos;
- se o
issuerconfigurado corresponde ao domíniotoken.acessocidadao.es.gov.br.
- se o