Pular para o conteúdo principal

Autenticação SMART on FHIR

O HubSaúde não usa senha nem chave de API. Nesta etapa acontecem duas coisas: seu sistema prova quem é, apresentando um certificado digital, e recebe permissão na forma de um token temporário, limitado ao que a sua instituição foi autorizada a acessar. Quem conduz a troca do outro lado é o servidor de autorização do HubSaúde, seguindo o padrão SMART Backend Services, construído sobre OAuth 2.0 e adotado internacionalmente para integração entre sistemas de saúde.

Na prática os SDKs oficiais fazem todo esse trabalho por você, e uma chamada de método basta. As seções abaixo servem para quando você precisar entender o que acontece por dentro, seja para investigar um erro, seja para implementar o fluxo sem eles.

Descoberta da API​

Em vez de fixar endereços no seu código, pergunte ao próprio servidor onde ficam as coisas e como a segurança está configurada. Os três endereços abaixo são públicos e você pode abri-los agora mesmo.

MétodoEndereçoDescrição
GET/metadataCapability Statement FHIR R4 do HubSaúde
GET/.well-known/smart-configurationDescoberta OAuth2 / SMART
GET/cds-servicesDescoberta de serviços CDS Hooks

Esta documentação não monitora a disponibilidade dos serviços em tempo real.

Provando a identidade do seu sistema​

Esta é a parte de autenticação do fluxo: aqui seu sistema apenas demonstra quem é. A permissão de acesso vem depois, no passo seguinte.

Para provar que é quem diz ser, seu sistema monta um pequeno documento assinado, o client_assertion. Tecnicamente é um JWT (JSON Web Token): um texto dividido em três partes separadas por ponto (cabeçalho, conteúdo e assinatura). A assinatura é gerada com a chave privada do seu certificado; o HubSaúde a confere com a chave pública já cadastrada no credenciamento, e só quem possui a chave privada correspondente consegue produzi-la corretamente. É essa assinatura que prova que o pedido veio do seu sistema, e o documento vale por poucos segundos.

Os SDKs oficiais montam e assinam esse documento sozinhos, então você não precisa construí-lo à mão. Conhecer o que ele contém ajuda a investigar falhas de autenticação e atende a exigências de auditoria. As duas primeiras partes (cabeçalho e conteúdo) não são criptografadas, apenas codificadas: qualquer um consegue lê-las. É nelas que ficam as seguintes informações:

Cabeçalho​

Diz qual algoritmo assinou o documento. O padrão é RS384, e o HubSaúde aceita apenas RS384 ou ES384. Vem acompanhado de typ: "JWT". Informe também o kid sempre que puder: ele identifica qual das suas chaves foi usada e passa a ser obrigatório quando há mais de uma chave registrada. Sem ele, o servidor responde 401 invalid_client.

Conteúdo​

Identifica quem pede e a quem se destina: iss e sub trazem o client_id, enquanto aud aponta o endereço do token. iat e exp delimitam a validade, por padrão 60 segundos e no máximo 300. O jti é um número de série que nunca se repete entre pedidos. Já hub_ctx é opcional e declara o Guia de Implementação pretendido, no formato {ig, versao}.

Trocando por um access token​

Aqui vem a parte de autorização. Com o documento assinado em mãos, o SDK o envia ao servidor de autorização e recebe o token de acesso de volta. É um POST em formato de formulário (application/x-www-form-urlencoded) com os campos grant_type=client_credentials, client_id, client_assertion_type, client_assertion e scope, este último omitido quando vazio.

O campo scope declara o que você pretende acessar, mas quem decide é o servidor: ele concede no máximo o que já estava pré-autorizado para o seu cadastro no credenciamento.

Apenas o código HTTP 200 significa sucesso. Se vier 429, o servidor está pedindo que você espere, e os SDKs não repetem a tentativa sozinhos nesse caso.

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()

Cache, renovação e mTLS​

Pedir um token novo a cada chamada seria lento e desnecessário, então o SDK guarda o token e o reaproveita enquanto ele valer. O cache é separado por scope, e o token é considerado válido enquanto agora + margem < expiração, com margem padrão de 30 segundos. Nesse intervalo, chamadas repetidas não geram tráfego de rede.

Token preso ao certificado​

Numa conexão HTTPS comum, só o servidor comprova sua identidade com um certificado. No mTLS (TLS mútuo), o cliente, ou seja, o seu sistema, também apresenta um certificado ao se conectar. Quando isso acontece, o token emitido pelo HubSaúde fica atrelado a esse certificado (campo cnf.x5t#S256, definido pela RFC 8705). Na prática, um token interceptado não serve a mais ninguém: só quem apresentar o mesmo certificado consegue usá-lo. Veja como isso aparece no Envio de Recurso.

Quando o token deixa de valer​

Um 401 numa chamada FHIR normalmente significa que o token guardado não vale mais. Descarte o cache daquele scope e peça um novo. Se o 401 se repetir com o token recém-obtido, pare de tentar: o problema está na credencial, não no cache.

Descartando o token guardado​

Os exemplos abaixo fazem os dois passos em sequência: primeiro descartam o token que está no cache para aquele scope, depois pedem um novo ao servidor. O primeiro passo é indispensável, porque enquanto o horário de expiração não chega o SDK considera o token válido e devolveria de novo exatamente o mesmo que acabou de ser recusado.

client.invalidate_cache("system/Patient.rs")
token_renovado = client.obtain_token(scope="system/Patient.rs")

Erros comuns​

SituaçãoCausaO que fazer
401 invalid_clientCliente tem múltiplas chaves registradas e o assertion não informa qualConfigurar keyId no SDK
401Certificado mTLS ausente ou divergente do cadastradoConferir o par chave/certificado usado pelo SDK
429Limite de requisições atingidoNão há repetição automática: aguarde o Retry-After e tente de novo
Erro de assinatura (SigningException/SigningError)Falha criptográfica na estratégia de assinatura configuradaVerificar formato/senha da chave PEM ou a configuração do HSM