Pular para o conteúdo principal

SDK Python

Biblioteca cliente Python (hubsaude-client) para obtenção de access tokens via SMART Backend Services.

Instalação​

Ainda não publicado no PyPI. Instale a partir do código-fonte (branch develop):

git clone https://github.com/sesgo-ti/hubsaude-cliente-python.git
cd hubsaude-cliente-python
pip install -e .

O extra opcional hsm (pip install "hubsaude-client[hsm]") traz a dependência python-pkcs11, necessária apenas para assinatura via HSM/smart token.

Uso básico​

SmartTokenClientBuilder monta o cliente passo a passo e valida a configuração antes de criar a instância. Reutilize o mesmo cliente durante todo o ciclo de vida da aplicação e chame close() uma única vez ao encerrar, ou use o gerenciador de contexto with.

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

from hubsaude_client.builder import SmartTokenClientBuilder

client = (
SmartTokenClientBuilder()
.client_id("meu-client-id")
.fhir_base("https://hub.saude.go.gov.br")
.private_key_pem("/caminho/para/chave-privada.pem")
.build()
)

resultado = client.obtain_token(scope="system/Patient.rs")
print(resultado)

client.close()

Endpoint de token explícito​

Se preferir fixar o endereço de token, use .token_endpoint no lugar de .fhir_base:

from hubsaude_client.builder import SmartTokenClientBuilder

client = (
SmartTokenClientBuilder()
.client_id("meu-client-id")
.token_endpoint("https://hub.saude.go.gov.br/auth/token")
.private_key_pem("/caminho/para/chave-privada.pem")
.build()
)

resultado = client.obtain_token(scope="system/Patient.rs")
print(resultado)

client.close()

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​

from hubsaude_client.builder import SmartTokenClientBuilder

client = (
SmartTokenClientBuilder()
.fhir_base("https://localhost:8443")
.client_id("meu-sistema")
.private_key_pem("client-key.pem")
.certificate_pem("client-cert.pem")
.server_trust_anchor("simulador-server.pem")
.build()
)

token = client.obtain_token("system/Patient.rs")
client.close()

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

  • .fhir_base 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;
  • .server_trust_anchor 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 .client_key_store(caminho, senha), descrito em PKCS#12 direto.

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 um contrato simples, hubsaude_client.SigningStrategy (um Protocol com um único método, sign(bytes) -> bytes), e já traz pronta uma factory para as quatro fontes mais comuns em hubsaude_client.strategy_factory.

PEM com senha​

client = (
SmartTokenClientBuilder()
.client_id("meu-client-id")
.token_endpoint("https://hub.saude.go.gov.br/auth/token")
.private_key_pem("/caminho/chave-encrypted.pem", password=bytearray(b"minha-senha"))
.build()
)

PKCS#12 direto​

Um único arquivo (.pfx/.p12) já reúne a chave e o certificado, protegido por senha. .client_key_store(path, password) resolve os dois de uma vez: a assinatura e o certificado de cliente para mTLS.

client = (
SmartTokenClientBuilder()
.client_id("meu-client-id")
.token_endpoint("https://hub.saude.go.gov.br/auth/token")
.client_key_store("certificado.pfx", "senha-pfx")
.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. Requer o extra opcional hsm; o SDK mantém apenas um handle de sessão PKCS#11.

from hubsaude_client.strategy_factory import from_pkcs11

strategy = from_pkcs11(
pkcs11_module_path="/usr/lib/softhsm/libsofthsm2.so",
token_label="meu-token",
key_label="minha-chave-hsm",
user_pin="123456",
)

client = (
SmartTokenClientBuilder()
.client_id("meu-client-id")
.token_endpoint("https://hub.saude.go.gov.br/auth/token")
.signing_strategy(strategy)
.build()
)

Configuração completa​

Método do builderObrigatórioPadrãoObservações
.token_endpoint(url)sim¹—URL completa do endpoint de token
.fhir_base(url)sim¹—Base FHIR para descoberta automática
.client_id(id)sim—Emitido pelo Ganesha
.private_key_pem(path, password=None)sim²—Caminho do PEM da chave privada
.signing_strategy(strategy)sim²—Estratégia pronta (HSM, cofre etc.)
.certificate_pem(path)não³—Certificado do cliente (PEM)
.client_key_store(path, password)não—mTLS via bundle PKCS#12
.server_trust_anchor(path)nãotrust store do sistemaPEM ou certificado X.509
.tls_protocol(protocolo)nãoTLSv1.3Ex.: TLSv1.2
.jwt_algorithm(alg)nãoRS384HubSaúde aceita RS384/ES384
.key_id(kid)não—Inclui kid no header do JWT
.hub_context(ig, versao)não—Inclui o claim hub_ctx
.connect_timeout(timedelta)não10sConexão TCP
.request_timeout(timedelta)não30sRequisição HTTP completa
.assertion_ttl_seconds(n)não60Deveria ser ≤300
.max_retries(n)não3Tentativas totais
.enable_token_cache(bool)nãotrueAtiva ou desativa o cache de tokens
.token_cache_margin_seconds(n)não30Margem de renovação antes da expiração
.token_cache_max_entries(n)não1000Descarte LRU por scope

¹ Exatamente um entre token_endpoint e fhir_base. ² Exatamente um entre private_key_pem e signing_strategy. ³ Obrigatório apenas para mTLS via chave em memória.

Exceções​

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

Repositório e especificação​