# Jak zaimplementować zgodę pacjenta z SMART on FHIR

> Tutorial: SMART on FHIR z OAuth 2.1 i PKCE krok po kroku — odkrywanie, rejestracja aplikacji, ekran zgody, wymiana tokenów, wymuszone zakresy, rotacja odświeżania i odwołanie — oraz co implementuje Anpheros.

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

**SMART on FHIR to standardowy sposób, w jaki aplikacja uzyskuje zgodę osoby na dostęp do jej rekordu FHIR: OAuth 2.1 z PKCE do autoryzacji, zakresy określające dokładnie, co można odczytać lub zapisać, oraz dokument odkrywania informujący aplikację, dokąd ma się udać.** Ten tutorial przeprowadzi przez cały przepływ z Anpheros, krok po kroku z `curl`: odkrywanie, rejestracja aplikacji, wysłanie osoby na ekran zgody, wymiana kodu, wywołanie API w ramach przyznanych zakresów, odświeżanie i co się dzieje, gdy osoba odwoła dostęp. Anpheros to backend SMART on FHIR: hostuje serwer autoryzacji, ekran zgody i serwer FHIR R4, dzięki czemu nie musisz tworzyć własnego interfejsu użytkownika logowania ani zgody.

## Dlaczego zgoda, a nie tylko klucz API

Klucz API umożliwia dostęp do danych pacjentów, które Twój projekt utworzył. Istniejące rekordy pacjenta (jego własne dane, zebrane przez inne aplikacje, kliniki i laboratoria) są jego własnością i może nimi zarządzać. Dzięki SMART on FHIR:

- pacjent widzi, w swoim języku, która aplikacja prosi o dostęp, czego chce odczytać lub zapisać, w jakim celu i na jak długo;
- Twoja aplikacja otrzymuje dostęp tylko do tych typów zasobów i akcji, i tylko dla tego jednego rekordu;
- każdy dostęp jest rejestrowany i widoczny dla pacjenta, który może go w każdej chwili odwołać;
- zgoda jest również przechowywana jako zasób FHIR `Consent`.

Model stojący za tym rozwiązaniem jest opisany w [Healthcare API with patient consent](https://developers.anpheros.com/pl/guides/healthcare-api-patient-consent) i [Consent and access model](https://developers.anpheros.com/pl/guides/consent).

## Krok 1: odkrywanie

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

Odpowiedź zawiera listę punktów końcowych i informacje o tym, co serwer obsługuje (skrócone):

```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"]}
```

Biblioteki klienckie SMART odczytują ten dokument i nie wymagają żadnej dodatkowej konfiguracji.

## Krok 2: Rejestracja aplikacji

W [panelu administracyjnym](https://platform.anpheros.com/dashboard/) otwórz swój projekt i dodaj aplikację wraz z jej URI przekierowania. Alternatywnie, możesz to zrobić za pomocą Admin API:

```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", …}
```

Użyj `public` dla aplikacji mobilnych i przeglądarkowych, które nie mogą przechowywać sekretu i polegają na PKCE. Użyj `confidential` dla serwera; jego `client_secret` jest wyświetlany tylko raz. Nazwa, cel i link do polityki prywatności to informacje, które użytkownik widzi na ekranie zgody.

## Krok 3: Przekierowanie użytkownika do ekranu zgody

Utwórz parę PKCE. Weryfikator pozostaje u Ciebie; podróżuje tylko jego skrót (hash):

```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 '=')
```

Następnie otwórz ten adres w przeglądarce użytkownika (dodano podziały wierszy dla czytelności):

```
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
```

Poproś tylko o to, czego potrzebujesz. Ta aplikacja odczytuje wyniki laboratoryjne i diagnozy, nic więcej. `offline_access` zwraca token odświeżający, dzięki czemu użytkownik nie musi ponownie zatwierdzać dostępu co 30 minut.

Użytkownik loguje się do Anpheros, czyta żądanie w języku prostym, wybiera, który rekord udostępnić (własny, członka rodziny, którym się opiekuje, lub ten, który Twoja aplikacja utworzyła dla niego) oraz jak długo ma trwać dostęp, a następnie zezwala lub odmawia. Użytkownik wraca do Twojego URI przekierowania:

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

Sprawdź, czy `state` jest wartością, którą wysłałeś wcześniej, przed użyciem kodu.

## Krok 4: wymiana kodu na tokeny

```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` wymienia przyznane uprawnienia. Zachowaj je wraz z tokenami i wyświetlaj tylko funkcje, które obejmują.
- `patient` to identyfikator rekordu dla Twojej aplikacji. Jest on parzysty: inna aplikacja widzi tę samą osobę pod innym identyfikatorem.
- `id_token` to token OpenID Connect, którego pole `fhirUser` nazywa zasób pacjenta.
- Kod działa raz i tylko z pasującym `code_verifier`.

## Krok 5: Wywołanie API w ramach zakresów

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

Wyniki laboratoryjne wracają jak zwykle. Poproś o coś spoza przyznanego zakresu, na przykład o leki:

```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."}]}
```

Jest to `403`. Wyszukiwania w ramach przyznanego zakresu są również filtrowane: z `Observation.rs?category=laboratory`, wyszukiwanie wszystkich obserwacji zwraca tylko laboratoryjne. Żaden inny pacjent nie istnieje dla tego tokenu (`404`). Widok REST (`/v1`) i [API kontekstu](https://developers.anpheros.com/pl/guides/llm-healthcare-data) stosują te same zakresy.

## Krok 6: odświeżanie

Tokeny dostępu są ważne przez 30 minut. Tokeny odświeżania są ważne przez 30 dni i rotują przy każdym użyciu:

```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
```

Otrzymujesz nowy token dostępu i nowy token odświeżania. Natychmiast zapisz nowy token. Ponowne użycie starego tokena odświeżania jest traktowane jako kradzież: kończy się błędem `400` i unieważnia całe przyznanie.

## Krok 7: odwołanie

Osoba może w dowolnym momencie odwołać Twój dostęp z poziomu Anpheros, a Ty możesz go odwołać samodzielnie, na przykład gdy osoba odłączy się w Twojej aplikacji:

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

Od tego momentu każde wywołanie z tym upoważnieniem zwraca `401`. Obsłuż to, pokazując osobie, że połączenie zostało zakończone i oferując ponowne połączenie. Zasubskrybuj [webhook](https://developers.anpheros.com/pl/guides/webhooks) `consent.revoked`, aby dowiedzieć się o tym bez czekania na nieudane wywołanie.

## Z użyciem SDK

[SDK w językach TypeScript i Dart](https://developers.anpheros.com/pl/guides/sdks) wykonują za Ciebie kroki od 3 do 6: `OAuthFlow.authorizeUrl` z wygenerowaną parą PKCE, `exchange` przy wywołaniu zwrotnym oraz automatyczne odświeżanie z rotacją. Pełne przykłady: [Jak zbudować aplikację AI w służbie zdrowia z backendem FHIR](https://developers.anpheros.com/pl/guides/build-ai-healthcare-app) (TypeScript) i [Jak zbudować aplikację w służbie zdrowia z użyciem Fluttera](https://developers.anpheros.com/guides/healthcare-app-flutter) (Dart).

## Co implementuje Anpheros

| Część SMART | W Anpheros |
|---|---|
| Discovery | `/.well-known/smart-configuration` na bazie FHIR, z obsługiwanymi punktami końcowymi, zakresami i metodami PKCE |
| Launch | uruchomienie samodzielne (aplikacja uruchamia się, a następnie prosi o dostęp); uruchomienie z poziomu systemu klinicznego EHR nie jest oferowane |
| Autoryzacja | OAuth 2.1 z wymaganym PKCE, przepływ kodu autoryzacji |
| Zakresy | zakresy pacjenta SMART v2, `patient/<Resource>.<cruds>` z filtrami kategorii, plus `openid` i `fhirUser` |
| Tożsamość | OpenID Connect `id_token` wskazujący pacjenta jako zasób FHIR |
| Zgoda | hostowany ekran zgody w języku pacjenta, z czasem trwania wybranym przez pacjenta, odzwierciedlony jako FHIR `Consent` |
| Tokeny | 30-minutowe tokeny dostępu, rotujące 30-dniowe tokeny odświeżania powiązane ze zgodą, odwołanie |
| Zgodność | oświadczenie o możliwościach deklaruje usługę bezpieczeństwa SMART; grupa "Standalone Launch" zestawu testowego Inferno SMART App Launch STU2 przechodzi 22 z 22 testów (uruchomienie z 28 września 2026); pozostałe grupy i zestawy testowe Inferno nie zostały uruchomione |

Pisanie działa w ten sam sposób: pisanie zakresów (`patient/Observation.c`, `.u`, `.d`) pozwala aplikacji tworzyć, aktualizować lub usuwać dane w rekordzie. Wszystko, co jest zapisywane, zawiera Twoją aplikację jako autora, ponowne próby z kluczem idempotencji nigdy nie duplikują pomiaru, a usunięcia są miękkie i zachowują historię ([Medical data API](https://developers.anpheros.com/pl/guides/medical-data-api)).

## Czego jeszcze nie ma

- Uruchomienie EHR (aplikacja otwierana z poziomu systemu szpitalnego z kontekstem uruchomienia).
- `system/` zakresów (scopes) dla usług backendowych; organizacje zamiast tego używają kluczy API.
- Eksport danych masowych (`$export`); dostępny jest eksport `$everything` dla pacjenta.

Są one wymienione wraz z pozostałymi w sekcji [Wersjonowanie i wycofywanie](https://developers.anpheros.com/pl/guides/versioning), a oświadczenie o możliwościach (capability statement) jest zawsze autorytatywnym źródłem informacji.

## Często zadawane pytania

### Czym jest SMART on FHIR?
Otwarty standard, zbudowany na OAuth 2.0/2.1 i OpenID Connect, który definiuje, w jaki sposób aplikacja prosi o dostęp do rekordu FHIR, jakie zakresy (scopes) opisują ten dostęp i jak serwer reklamuje swoje punkty końcowe (endpoints). Dowolna biblioteka klienta obsługująca SMART może korzystać z dowolnego serwera obsługującego SMART.

### Czy potrzebuję PKCE?
Tak. Anpheros wymaga PKCE z `S256` dla każdego przepływu kodu autoryzacyjnego, zarówno dla klientów publicznych, jak i poufnych. Zapobiega to wykorzystaniu przechwyconego kodu autoryzacyjnego przez kogokolwiek innego.

### Co się stanie, jeśli osoba odmówi?
Osoba zostanie przekierowana z powrotem do Twojego URI przekierowania (redirect URI) z `error=access_denied` i Twoim `state`, ale bez kodu. Wyjaśnij, czego potrzebuje dana funkcja i pozwól jej spróbować ponownie; wywołania spoza przyznanego dostępu (grant) zawsze zwracają `403`.

### Czy rodzic może wyrazić zgodę dla dziecka?
Tak. Na ekranie zgody osoba może wybrać rekord, o który się troszczy, na przykład dziecka, jeśli jest on powiązany z jej kontem. Przyznany dostęp (grant) dotyczy tylko tego rekordu.

## Powiązane

- [Uwierzytelnianie i OAuth](https://developers.anpheros.com/pl/guides/authentication): klucze API, tokeny i ich okresy ważności w szczegółach
- [API medyczne z zgodą pacjenta](https://developers.anpheros.com/pl/guides/healthcare-api-patient-consent): jak zgoda wpływa na projekt Twojej aplikacji
- [Model zgody i dostępu](https://developers.anpheros.com/pl/guides/consent)
- [Platforma FHIR](https://developers.anpheros.com/pl/guides/fhir)
- [Tworzenie aplikacji medycznej](https://developers.anpheros.com/pl/guides/build-a-healthcare-app)
