SDK TypeScript
Biblioteca cliente TypeScript/Node.js (hubsaude-cliente-js, consumível também por JavaScript puro). O uso é exclusivamente em servidor, nunca em navegador ou app móvel.
Instalação
Ainda não publicado no registro npm público. Até a primeira publicação, instale a partir de um tarball gerado por npm pack no repositório, ou aponte para o Git diretamente.
npm install github:sesgo-ti/hubsaude-cliente-ts
Uso básico
createSmartTokenClient é a única forma de construção (a classe não tem construtor público). Chame close() uma vez no encerramento, ou use await using client = await createSmartTokenClient(...).
Informe a base do servidor: a biblioteca consulta /.well-known/smart-configuration e resolve o endpoint de token. Não combine fhirBase com tokenEndpoint.
import { createSmartTokenClient } from "hubsaude-cliente-js";
const client = await createSmartTokenClient({
fhirBase: "https://hub.saude.go.gov.br",
clientId: "meu-sistema",
privateKeyPem: "chave-privada.pem",
certificatePem: "certificado.pem",
});
const token = await client.obtainToken("system/Patient.rs");
Endpoint de token explícito
Se preferir fixar o endereço de token, use tokenEndpoint no lugar de fhirBase:
import { createSmartTokenClient } from "hubsaude-cliente-js";
const client = await createSmartTokenClient({
tokenEndpoint: "https://hub.saude.go.gov.br/auth/token",
clientId: "meu-sistema",
privateKeyPem: "chave-privada.pem",
certificatePem: "certificado.pem",
});
const token = await client.obtainToken("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á:
- o Simulador em execução, iniciado com
hubsaude sim start; - um certificado de teste (
client-cert.pem) e a respectiva chave (client-key.pem), gerados com o OpenSSL; - o sistema cadastrado no Simulador com o identificador
meu-sistemae a permissãosystem/Patient.rs; - o certificado do próprio Simulador (
simulador-server.pem), baixado do endereçohttps://localhost:8443/certs/simulador-server.pem.
Configurar a biblioteca
import { createSmartTokenClient } from "hubsaude-cliente-js";
const client = await createSmartTokenClient({
fhirBase: "https://localhost:8443",
clientId: "meu-sistema",
privateKeyPem: "client-key.pem",
certificatePem: "client-cert.pem",
serverTrustAnchor: "simulador-server.pem",
});
const token = await client.obtainToken("system/Patient.rs");
Em relação ao uso com a produção, há três diferenças:
fhirBaseaponta 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;
serverTrustAnchorfaz 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_identregue 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ção | Causa provável | O que fazer |
|---|---|---|
| Erro de certificado ao conectar, como falha na verificação da cadeia | O certificado do Simulador não foi informado | Baixe o simulador-server.pem e configure a âncora de confiança |
401 invalid_client informando que o certificado não corresponde ao cadastrado | O certificado usado é diferente do enviado no cadastro | Use o mesmo par de chave e certificado do cadastro |
401 invalid_client informando que o certificado de cliente é obrigatório | O certificado de cliente não foi configurado | Informe o certificado de teste na configuração da biblioteca |
| Erro de permissão ao pedir o token | A permissão solicitada não foi liberada no cadastro | Cadastre o sistema novamente incluindo a permissão desejada |
| O sistema deixa de ser reconhecido | O Simulador foi reiniciado e apagou os cadastros | Cadastre 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 o tipo SigningStrategy, uma função que recebe os bytes a assinar e devolve a assinatura, e já traz pronta a construção para as fontes mais comuns.
PEM com senha
const client = await createSmartTokenClient({
tokenEndpoint: "https://hub.saude.go.gov.br/auth/token",
clientId: "meu-sistema",
privateKeyPem: "chave-encrypted.pem",
privateKeyPassword: Buffer.from("minha-senha"),
});
PKCS#12 direto (recomendado para produção)
Um único arquivo (.pfx/.p12) já reúne a chave e o certificado, protegido por senha.
import { readFile } from "node:fs/promises";
import { createSmartTokenClient, fromPkcs12 } from "hubsaude-cliente-js";
const pfx = await readFile("certificado.pfx");
const client = await createSmartTokenClient({
tokenEndpoint: "https://hub.saude.go.gov.br/auth/token",
clientId: "meu-sistema",
signingStrategy: fromPkcs12(pfx, "senha-pfx"),
clientPfx: pfx,
clientPfxPassphrase: "senha-pfx",
});
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. Node não tem suporte nativo a PKCS#11 (o padrão usado para acessar o HSM), então pkcs11js entra como peer dependency opcional (npm install github:sesgo-ti/hubsaude-cliente-ts pkcs11js).
import { createSmartTokenClient, fromPkcs11 } from "hubsaude-cliente-js";
const signingStrategy = await fromPkcs11({
library: "/usr/lib/softhsm/libsofthsm2.so",
tokenLabel: "meu-token",
keyLabel: "minha-chave-hsm",
pin: "123456",
jwtAlgorithm: "ES384",
});
const client = await createSmartTokenClient({
tokenEndpoint: "https://hub.saude.go.gov.br/auth/token",
clientId: "meu-sistema",
signingStrategy,
});
Configuração completa
Todas as opções abaixo são propriedades do objeto passado a createSmartTokenClient(options).
| Opção | Obrigatório | Padrão | Observações |
|---|---|---|---|
tokenEndpoint | sim¹ | — | URL completa do endpoint de token |
fhirBase | sim¹ | — | Base FHIR para descoberta automática |
clientId | sim | — | Emitido pelo Ganesha |
privateKeyPem | sim² | — | Caminho do PEM da chave privada |
privateKeyPassword | não | — | Senha do PEM criptografado (Buffer) |
signingStrategy | sim² | — | Estratégia pronta (HSM, cofre etc.) |
certificatePem | não³ | — | Certificado do cliente (PEM) |
clientPfx / clientPfxPassphrase | não | — | mTLS via bundle PKCS#12 |
serverTrustAnchor | não | trust store do sistema | PEM ou certificado |
tlsProtocol | não | TLSv1.3 | Ex.: TLSv1.2 |
jwtAlgorithm | não | RS384 | HubSaúde aceita RS384/ES384 |
keyId | não | — | Inclui kid no header do JWT |
hubContext | não | — | Inclui o claim hub_ctx ({ig, versao}) |
connectTimeoutMs | não | 10000 | Conexão TCP |
requestTimeoutMs | não | 30000 | Requisição HTTP completa |
assertionTtlSeconds | não | 60 | Deveria ser ≤300 |
maxRetries | não | 3 | Tentativas totais |
enableTokenCache | não | true | Ativa ou desativa o cache de tokens |
tokenCacheMarginSeconds | não | 30 | Margem de renovação antes da expiração |
tokenCacheMaxEntries | não | 1000 | Descarte 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
| Tipo | Uso |
|---|---|
SmartTokenError | Configuração criptográfica inválida, resposta HTTP/JSON inválida, algoritmo não suportado, ou rejeição confirmada do certificado de cliente |
SigningError | Falha da estratégia criptográfica ao assinar o client_assertion |