Pular para o conteúdo principal

SDK C#

Biblioteca cliente C#/.NET (pacote NuGet HubSaude.Cliente).

Instalação​

O nupkg (e o SBOM CycloneDX) saem da GitHub Release da tag; a publicação no nuget.org ainda não faz parte do repositório. Baixe o .nupkg da release e registre-o como fonte local antes de referenciar o pacote.

dotnet nuget add source ./caminho/para/pasta-com-o-nupkg --name hubsaude-local
dotnet add package HubSaude.Cliente --version 0.4.0 --source hubsaude-local

Isso adiciona ao seu projeto:

<PackageReference Include="HubSaude.Cliente" Version="0.4.0" />

Uso básico​

SmartTokenClient.CreateBuilder() é a única forma de construção, já que a classe não expõe construtores públicos. Implementa IDisposable/IAsyncDisposable.

Informe a base do servidor: a biblioteca consulta /.well-known/smart-configuration e resolve o endpoint de token. Não combine .FhirBase com .TokenEndpoint.

await using var client = SmartTokenClient.CreateBuilder()
.FhirBase("https://hub.saude.go.gov.br")
.ClientId("meu-sistema")
.PrivateKeyPem("chave-privada.pem")
.CertificatePem("certificado.pem")
.Build();

string token = await client.ObtainTokenAsync("system/Patient.rs");

Endpoint de token explícito​

Se preferir fixar o endereço de token, use .TokenEndpoint no lugar de .FhirBase:

await using var client = SmartTokenClient.CreateBuilder()
.TokenEndpoint("https://hub.saude.go.gov.br/auth/token")
.ClientId("meu-sistema")
.PrivateKeyPem("chave-privada.pem")
.CertificatePem("certificado.pem")
.Build();

string token = await client.ObtainTokenAsync("system/Patient.rs");

Testar com o Simulador​

O Simulador reproduz o HubSaúde no seu computador e permite testar a biblioteca antes de receber a credencial oficial. Ele exige os mesmos cuidados de segurança da produção, então a configuração é praticamente a mesma: muda apenas o endereço, a origem do certificado e a confiança no servidor.

Antes de executar o código​

Siga os passos de Preparar seu sistema para o Simulador. Ao final deles, você terá:

  1. o Simulador em execução, iniciado com hubsaude sim start;
  2. um certificado de teste (client-cert.pem) e a respectiva chave (client-key.pem), gerados com o OpenSSL;
  3. o sistema cadastrado no Simulador com o identificador meu-sistema e a permissão system/Patient.rs;
  4. o certificado do próprio Simulador (simulador-server.pem), baixado do endereço https://localhost:8443/certs/simulador-server.pem.

Configurar a biblioteca​

await using var client = SmartTokenClient.CreateBuilder()
.FhirBase("https://localhost:8443")
.ClientId("meu-sistema")
.PrivateKeyPem("client-key.pem")
.CertificatePem("client-cert.pem")
.ServerTrustAnchor("simulador-server.pem")
.Build();

string token = await client.ObtainTokenAsync("system/Patient.rs");

Em relação ao uso com a produção, há três diferenças:

  • .FhirBase aponta para o Simulador, e a biblioteca descobre sozinha os demais endereços;
  • a chave e o certificado são os de teste, cadastrados no Simulador, e o identificador é o informado no cadastro;
  • .ServerTrustAnchor faz a biblioteca confiar no certificado do Simulador, que não é emitido por uma autoridade reconhecida.

Se você gerou o certificado de teste com o Java keytool, a chave fica dentro do arquivo client-keystore.p12. Nesse caso, use o PKCS#12, descrito em Fontes de chave suportadas.

Passar para a produção​

Depois que o credenciamento for aprovado, ajuste a mesma configuração:

  • troque o endereço do Simulador por https://hub.saude.go.gov.br;
  • use o client_id entregue no credenciamento;
  • substitua a chave e o certificado de teste pelos da instituição;
  • remova a linha da âncora de confiança: o certificado do HubSaúde já é reconhecido automaticamente.

Problemas comuns no Simulador​

SituaçãoCausa provávelO que fazer
Erro de certificado ao conectar, como falha na verificação da cadeiaO certificado do Simulador não foi informadoBaixe o simulador-server.pem e configure a âncora de confiança
401 invalid_client informando que o certificado não corresponde ao cadastradoO certificado usado é diferente do enviado no cadastroUse o mesmo par de chave e certificado do cadastro
401 invalid_client informando que o certificado de cliente é obrigatórioO certificado de cliente não foi configuradoInforme o certificado de teste na configuração da biblioteca
Erro de permissão ao pedir o tokenA permissão solicitada não foi liberada no cadastroCadastre o sistema novamente incluindo a permissão desejada
O sistema deixa de ser reconhecidoO Simulador foi reiniciado e apagou os cadastrosCadastre o sistema novamente

Fontes de chave suportadas​

Sua chave privada pode estar em diferentes lugares: um arquivo, um cofre de segredos ou um dispositivo de hardware. O SDK abstrai isso com a interface ISigningStrategy (um único método que assina bytes), e SigningStrategyFactory já traz pronta a construção para as fontes mais comuns.

PEM com senha​

var senha = "segredo".ToCharArray();
await using var client = SmartTokenClient.CreateBuilder()
.TokenEndpoint("https://hub.saude.go.gov.br/auth/token")
.ClientId("meu-sistema")
.PrivateKeyPem("chave-privada.pem")
.PrivateKeyPassword(senha)
.Build();

PKCS#12 direto (recomendado para produção)​

Um único arquivo (.pfx/.p12) já reúne a chave e o certificado, protegido por senha.

await using var client = SmartTokenClient.CreateBuilder()
.TokenEndpoint("https://hub.saude.go.gov.br/auth/token")
.ClientId("meu-sistema")
.ClientPkcs12("certificado.pfx", "alias-da-chave", "senha-pfx".ToCharArray())
.Build();

HSM via PKCS#11​

Um HSM (Hardware Security Module) é um dispositivo dedicado que guarda a chave e nunca a expõe: toda assinatura acontece dentro dele, acessado aqui pelo padrão PKCS#11.

await using var client = SmartTokenClient.CreateBuilder()
.TokenEndpoint("https://hub.saude.go.gov.br/auth/token")
.ClientId("meu-sistema")
.SigningStrategy(SigningStrategyFactory.FromPkcs11(new Pkcs11Options
{
Library = "/usr/lib/softhsm/libsofthsm2.so",
Pin = pinDoToken,
TokenLabel = "hubsaude",
KeyLabel = "jwt-key",
JwtAlgorithm = "RS384",
}))
.ClientPkcs12("cliente-mtls.pfx", "alias-do-cert", senhaPfx)
.Build();

Configuração completa​

Método do builderObrigatórioPadrãoObservações
.TokenEndpoint(url)sim¹—URL completa do endpoint de token
.FhirBase(url)sim¹—Base FHIR para descoberta automática
.ClientId(id)sim—Emitido pelo Ganesha
.PrivateKeyPem(path)sim²—Caminho do PEM da chave privada
.PrivateKeyPassword(char[])não—Senha do PEM criptografado
.SigningStrategy(strategy)sim²—Estratégia pronta (HSM, cofre etc.)
.CertificatePem(path)não³—Certificado do cliente (PEM)
.ClientPkcs12(path, alias, senha)não—mTLS via bundle PKCS#12
.ServerTrustAnchor(path)nãotrust store do sistemaPEM ou certificado
.TlsProtocol(protocolo)nãoTLSv1.3Ex.: TLSv1.2
.JwtAlgorithm(alg)nãoRS384HubSaúde aceita RS384/ES384
.KeyId(kid)não—Inclui kid no header do JWT
.HubContext(ig, versao)não—Inclui o claim hub_ctx
.ConnectTimeout(TimeSpan)não10sConexão TCP
.RequestTimeout(TimeSpan)não30sRequisição HTTP completa
.AssertionTtlSeconds(n)não60Deveria ser ≤300
.MaxRetries(n)não3Tentativas totais
.EnableTokenCache(bool)nãotrueAtiva ou desativa o cache de tokens
.TokenCacheMarginSeconds(n)não30Margem de renovação antes da expiração
.TokenCacheMaxEntries(n)não1000Descarte LRU por scope

¹ Exatamente um entre TokenEndpoint e FhirBase. ² Exatamente um entre PrivateKeyPem e SigningStrategy. ³ Obrigatório apenas para mTLS via chave em memória.

Exceções​

TipoUso
SmartTokenExceptionConfiguração criptográfica inválida, resposta HTTP/JSON inválida ou algoritmo não suportado
SigningExceptionFalha da estratégia criptográfica ao assinar o client_assertion

Repositório e especificação​