# Como implementar o consentimento do paciente com SMART on FHIR

> Tutorial: SMART on FHIR com OAuth 2.1 e PKCE passo a passo — descoberta, registo da aplicação, ecrã de consentimento, troca de tokens, escopos aplicados, rotação de refresh e revogação — e o que a Anpheros implementa.

Source: https://developers.anpheros.com/pt/guides/smart-on-fhir-backend

**SMART on FHIR é a forma padrão de uma aplicação obter a permissão de uma pessoa para aceder ao seu registo FHIR: OAuth 2.1 com PKCE para a autorização, escopos que indicam exatamente o que pode ser lido ou escrito, e um documento de descoberta que informa a aplicação para onde ir.** Este tutorial executa todo o fluxo contra a Anpheros, passo a passo com `curl`: descoberta, registo de uma aplicação, envio da pessoa para o ecrã de consentimento, troca do código, chamada da API dentro dos escopos concedidos, refresh, e o que acontece quando a pessoa revoga o acesso. A Anpheros é o backend SMART on FHIR: hospeda o servidor de autorização, o ecrã de consentimento e o servidor FHIR R4, pelo que não escreve nenhuma UI de login ou consentimento própria.

## Porquê consentimento e não apenas uma chave de API

Uma chave de API alcança os pacientes que o seu projeto criou. O registo existente de uma pessoa (os seus próprios dados, recolhidos por outras aplicações, clínicas e laboratórios) é seu para partilhar. Com SMART on FHIR:

- a pessoa vê, na sua língua, qual a aplicação que pergunta, o que pretende ler ou escrever, para que finalidade e por quanto tempo;
- a sua aplicação obtém apenas esses tipos de recursos e ações, e apenas para esse registo específico;
- cada acesso é registado e visível para a pessoa, que o pode revogar a qualquer momento;
- a concessão é também armazenada como um recurso FHIR `Consent`.

O modelo subjacente é descrito em [Healthcare API with patient consent](https://developers.anpheros.com/pt/guides/healthcare-api-patient-consent) e [Consent and access model](https://developers.anpheros.com/pt/guides/consent).

## Passo 1: Descoberta

```bash
curl https://platform.anpheros.com/fhir/R4/.well-known/smart-configuration
```

A resposta lista os endpoints e o que o servidor suporta (resumido):

```json
{"issuer": "https://platform.anpheros.com",
 "authorization_endpoint": "https://platform.anpheros.com/oauth/authorize",
 "token_endpoint": "https://platform.anpheros.com/oauth/token",
 "revocation_endpoint": "https://platform.anpheros.com/oauth/revoke",
 "code_challenge_methods_supported": ["S256"],
 "scopes_supported": ["patient/*.rs", "patient/Patient.r", "patient/Observation.rs", "patient/Observation.rs?category=laboratory",
                      "patient/Observation.rs?category=vital-signs", "patient/Observation.c", "patient/Condition.rs",
                      "patient/MedicationStatement.rs", "patient/DocumentReference.rs", "patient/AllergyIntolerance.rs",
                      "offline_access", "launch/patient", "openid", "fhirUser"],
 "capabilities": ["launch-standalone", "client-public", "client-confidential-symmetric", "permission-patient",
                  "permission-offline", "context-standalone-patient", "sso-openid-connect"]}
```

As bibliotecas cliente SMART leem este documento e não necessitam de mais nenhuma configuração.

## Passo 2: registar a sua aplicação

No [painel de controlo](https://platform.anpheros.com/dashboard/), abra o seu projeto e adicione uma aplicação com o seu URI de redirecionamento. Ou através da API de Administração:

```bash
curl -X POST https://platform.anpheros.com/admin/projects/$PROJECT/applications \
     -H "Authorization: Bearer $FIREBASE_ID_TOKEN" -H "Content-Type: application/json" -d '{
  "name": "CardioAI", "client_type": "public",
  "redirect_uris": ["https://cardio.example/callback"],
  "purpose": "cardiology follow-up", "privacy_url": "https://cardio.example/privacy"
}'
```

```json
{"id": "app_…", "name": "CardioAI", "client_type": "public", "client_id": "client_Hg6CknNkYlMgN190", "client_secret": null,
 "redirect_uris": ["https://cardio.example/callback"], "purpose": "cardiology follow-up", "status": "active", …}
```

Utilize `public` para aplicações móveis e de navegador, que não podem manter um segredo e dependem de PKCE. Utilize `confidential` para um servidor; o seu `client_secret` é mostrado uma vez. O nome, propósito e link de privacidade são o que a pessoa vê no ecrã de consentimento.

## Passo 3: Enviar a pessoa para o ecrã de consentimento

Crie um par PKCE. O verificador fica consigo; apenas o seu hash é enviado:

```bash
VERIFIER=$(openssl rand -base64 64 | tr -d '=+/\n' | cut -c1-64)
CHALLENGE=$(printf %s "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')
```

Em seguida, abra este endereço no navegador da pessoa (quebras de linha adicionadas para leitura):

```
https://platform.anpheros.com/oauth/authorize?response_type=code
  &client_id=client_Hg6CknNkYlMgN190
  &redirect_uri=https://cardio.example/callback
  &scope=openid fhirUser patient/Observation.rs?category=laboratory patient/Condition.rs offline_access
  &state=8c1e…               ← a random value you check on return
  &code_challenge=$CHALLENGE&code_challenge_method=S256
  &purpose=treatment&lang=en
```

Peça o mínimo de que necessita. Esta aplicação lê resultados de laboratório e diagnósticos, nada mais. `offline_access` fornece um token de atualização, para que a pessoa não tenha de aprovar novamente a cada 30 minutos.

A pessoa inicia sessão no Anpheros, lê o pedido em linguagem clara, escolhe qual registo partilhar (o seu próprio, o de um membro da família de quem cuida, ou o que a sua aplicação criou para si) e por quanto tempo o acesso dura, e depois permite ou nega. Regressa ao seu URI de redirecionamento:

```
https://cardio.example/callback?code=…&state=8c1e…
```

Verifique se `state` é o valor que enviou antes de usar o código.

## Passo 4: Trocar o código por tokens

```bash
curl -X POST https://platform.anpheros.com/oauth/token \
  -d grant_type=authorization_code -d client_id=client_Hg6CknNkYlMgN190 \
  -d code=$CODE -d code_verifier=$VERIFIER -d redirect_uri=https://cardio.example/callback
```

```json
{"access_token": "at_…", "token_type": "Bearer", "expires_in": 1800,
 "scope": "patient/Observation.rs?category=laboratory patient/Condition.rs openid fhirUser offline_access",
 "patient": "82bfd321-6a4d-4aea-943a-a62f4d81d419", "grant_id": "grant_…",
 "id_token": "eyJ…", "refresh_token": "rt_…"}
```

- `scope` lista o que foi concedido. Mantenha-o com os tokens e mostre apenas as funcionalidades que cobre.
- `patient` é o ID do registo para a sua aplicação. É par: outra aplicação vê a mesma pessoa sob um ID diferente.
- `id_token` é um token OpenID Connect cujo claim `fhirUser` nomeia o recurso do paciente.
- O código funciona uma vez, e apenas com o `code_verifier` correspondente.

## Passo 5: chamar a API dentro dos escopos

```bash
curl "https://platform.anpheros.com/fhir/R4/Observation?patient=$PATIENT&category=laboratory" -H "Authorization: Bearer $ACCESS_TOKEN"
```

Os resultados de laboratório retornam como habitual. Peça algo fora da concessão, como medicamentos:

```bash
curl "https://platform.anpheros.com/fhir/R4/MedicationStatement?patient=$PATIENT" -H "Authorization: Bearer $ACCESS_TOKEN"
```

```json
{"resourceType": "OperationOutcome", "issue": [{"severity": "error", "code": "forbidden",
  "diagnostics": "The consent behind this token does not allow 's' on MedicationStatement."}]}
```

Isso é um `403`. As pesquisas dentro da concessão também são filtradas: com `Observation.rs?category=laboratory`, uma pesquisa por todas as observações retorna apenas as de laboratório. Qualquer outro paciente não existe para este token (`404`). A vista REST (`/v1`) e a [API de contexto](https://developers.anpheros.com/pt/guides/llm-healthcare-data) aplicam os mesmos escopos.

## Passo 6: refresh

Os tokens de acesso duram 30 minutos. Os tokens de refresh duram 30 dias e rodam a cada utilização:

```bash
curl -X POST https://platform.anpheros.com/oauth/token \
  -d grant_type=refresh_token -d client_id=client_Hg6CknNkYlMgN190 -d refresh_token=$REFRESH_TOKEN
```

Recebe um novo token de acesso e um novo token de refresh. Armazene o novo imediatamente. A reutilização de um token de refresh antigo é tratada como roubo: falha com `400` e revoga toda a concessão.

## Passo 7: revogação

A pessoa pode revogar o seu acesso a partir do Anpheros a qualquer momento, e pode revogá-lo você mesmo, por exemplo, quando ela se desconecta na sua aplicação:

```bash
curl -X POST https://platform.anpheros.com/oauth/revoke -d token=$REFRESH_TOKEN -d client_id=client_Hg6CknNkYlMgN190
```

A partir daí, todas as chamadas com essa concessão falham `401`. Lide com isso mostrando à pessoa que a ligação terminou e oferecendo-se para ligar novamente. Subscreva o [webhook](https://developers.anpheros.com/pt/guides/webhooks) `consent.revoked` para saber sem ter de esperar por uma chamada falhada.

## Com os SDKs

Os [SDKs TypeScript e Dart](https://developers.anpheros.com/pt/guides/sdks) realizam os passos 3 a 6 por si: `OAuthFlow.authorizeUrl` com um par PKCE gerado, `exchange` no callback, e refresh automático com rotação. Exemplos completos: [Como criar uma app de saúde com IA e um backend FHIR](https://developers.anpheros.com/pt/guides/build-ai-healthcare-app) (TypeScript) e [Como criar uma app de saúde com Flutter](https://developers.anpheros.com/guides/healthcare-app-flutter) (Dart).

## O que o Anpheros implementa

| Parte do SMART | No Anpheros |
|---|---|
| Discovery | `/.well-known/smart-configuration` na base FHIR, com os endpoints, scopes e métodos PKCE suportados |
| Launch | launch standalone (a aplicação inicia, depois pede acesso); launch EHR a partir de um sistema clínico não é oferecido |
| Autorização | OAuth 2.1 com PKCE obrigatório, fluxo de código de autorização |
| Scopes | scopes de paciente SMART v2, `patient/<Resource>.<cruds>` com filtros de categoria, mais `openid` e `fhirUser` |
| Identidade | um OpenID Connect `id_token` nomeando o paciente como um recurso FHIR |
| Consentimento | um ecrã de consentimento hospedado na língua do paciente, com a duração escolhida pelo paciente, espelhado como um FHIR `Consent` |
| Tokens | tokens de acesso de 30 minutos, tokens de refresh rotativos de 30 dias vinculados ao consentimento, revogação |
| Conformance | a declaração de capacidade declara o serviço de segurança SMART; o grupo "Standalone Launch" do kit de teste Inferno SMART App Launch STU2 passa 22 de 22 testes (execução de 28 de setembro de 2026); os outros grupos e kits de teste Inferno não foram executados |

A escrita funciona da mesma forma: escrever scopes (`patient/Observation.c`, `.u`, `.d`) permite que a sua aplicação crie, atualize ou elimine dentro do registo. Tudo o que é escrito carrega a sua aplicação como autor, retentativas com uma chave de idempotência nunca duplicam uma medição, e as eliminações são suaves e mantêm o histórico ([Medical data API](https://developers.anpheros.com/pt/guides/medical-data-api)).

## O que ainda não existe

- Lançamento EHR (a aplicação aberta a partir de um sistema hospitalar com um contexto de lançamento).
- `system/` escopos para serviços de backend; as organizações usam chaves de API em vez disso.
- Exportação de dados em massa (`$export`); `$everything` num paciente está disponível.

Estes são listados com o resto em [Versioning and deprecation](https://developers.anpheros.com/pt/guides/versioning), e a declaração de capacidade é sempre a fonte autoritativa.

## Perguntas frequentes

### O que é SMART on FHIR?
Um padrão aberto, construído sobre OAuth 2.0/2.1 e OpenID Connect, que define como uma aplicação solicita acesso a um registo FHIR, quais os âmbitos (scopes) que descrevem esse acesso e como o servidor anuncia os seus pontos de extremidade (endpoints). Qualquer biblioteca cliente compatível com SMART pode usar qualquer servidor compatível com SMART.

### Preciso de PKCE?
Sim. O Anpheros requer PKCE com `S256` para todos os fluxos de código de autorização, tanto para clientes públicos como confidenciais. Impede que um código de autorização intercetado seja utilizado por qualquer outra pessoa.

### O que acontece se a pessoa disser não?
Regressam ao seu URI de redirecionamento com `error=access_denied` e o seu `state`, e sem código. Explique o que a funcionalidade necessita e deixe-os tentar novamente; chamadas fora de uma concessão (grant) respondem sempre com `403`.

### Um progenitor pode dar consentimento para um filho?
Sim. No ecrã de consentimento, uma pessoa pode escolher um registo de que cuida, como o de um filho, se este estiver associado à sua conta. A concessão (grant) aplica-se apenas a esse registo.

## Relacionado

- [Autenticação e OAuth](https://developers.anpheros.com/pt/guides/authentication): Chaves de API, tokens e tempos de vida em detalhe
- [API de Saúde com consentimento do paciente](https://developers.anpheros.com/pt/guides/healthcare-api-patient-consent): como o consentimento altera o design da sua aplicação
- [Modelo de consentimento e acesso](https://developers.anpheros.com/pt/guides/consent)
- [Plataforma FHIR](https://developers.anpheros.com/pt/guides/fhir)
- [Criar uma aplicação de saúde](https://developers.anpheros.com/pt/guides/build-a-healthcare-app)
