Pular para o conteúdo principal

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:

  1. como obter um token com client_credentials;
  2. como chamar uma API protegida;
  3. 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 HttpClient reutilizável.
  • Não faça cache de token além do tempo de expiração.
  • Nunca exponha client_secret em frontend.
  • Não aceite token emitido para outra API.
  • Em caso de erro 401 ou 403, verifique primeiro:
    • se o aud esperado está correto;
    • se os scopes concedidos à aplicação estão corretos;
    • se o issuer configurado corresponde ao domínio token.acessocidadao.es.gov.br.