Configure your Shiny app to access a hospital's FHIR API. Start with
smart_discover(), then supply the app registration and requested permissions.
The result is an OAuthClient for oauth_module_server() or
oauth_connections(), with an approved API named "fhir".
Usage
smart_client(
discovery,
client_id,
redirect_uri,
scopes,
required_scopes = scopes,
launch = c("standalone", "ehr"),
identity = c("none", "openid", "fhirUser"),
allow_v1_scopes = FALSE,
online_access_policy = c("online_only", "allow_offline"),
token_auth_style = c("public", "header", "private_key_jwt"),
client_secret = character(),
client_assertion_private_key = NULL,
client_assertion_private_key_kid = NULL,
client_assertion_alg = "RS384",
authorization_method = "GET",
response_mode = NULL,
authorization_server_mode = "single",
authorization_server_redirect_uris = character(),
initial_expires_in_fallback = NULL,
label = "FHIR server",
state_store = cachem::cache_mem(max_age = 300),
state_key = random_urlsafe(128),
state_payload_max_age = 300
)Arguments
- discovery
A plain snapshot returned by
smart_discover(). Its metadata and endpoint policy are revalidated locally; this performs no network calls.- client_id, redirect_uri
App registration values. The callback must use HTTPS, except for the snapshot's explicit HTTP loopback development policy.
- scopes
Permissions to request, without automatic wildcard/offline access. Standalone patient scopes require
launch/patient. EHR clients addlaunch.online_accessrequires EHR launch andpermission-online;offline_accessrequirespermission-offlinein either launch mode. Each resource scope spelling must be advertised throughpermission-v2or, for v1 spellings,permission-v1withallow_v1_scopes = TRUE. A SMART scope comparison supports at most 256 distinct scopes on each side and 64 KiB (65,536 bytes) of combined scope text. Larger comparisons are rejected, including during token acceptance and refresh.- required_scopes
Minimum permissions, defaulting to
scopes. Pass a subset to accept reduced grants as limited connections. Identity scopes are always required when identity is enabled. Unsupported comparisons are rejected.- launch
"standalone"or"ehr", matching the registered app flow.- identity
"none"(default),"openid"for a validated OIDC subject, or"fhirUser"to also require the user's FHIR reference."openid"does not interpret afhirUserclaim or populatesmart_context()[["fhirUser"]]. A validatedfhirUserclaim may be an absolute URL or a supported resource instance reference relative to this client's FHIR base, such as"Practitioner/example"or"Practitioner/example/_history/2". Versioned references retain their version.- allow_v1_scopes
Explicit compatibility flag enabling
.read,.writeand.*. Requesting these spellings requirespermission-v1; requesting v2 spellings requirespermission-v2, including when this flag is enabled. DefaultFALSE.- online_access_policy
"online_only"(default) or"allow_offline". SMART permits anonline_accessrequest to negotiateoffline_access. Opt in to"allow_offline"to accept that longer-lived permission in place of requiredonline_access. The default rejects this substitution, even whenonline_accessis optional. Explicitly requestingoffline_accessalso authorizes offline persistence. Granted scopes retain their actual spelling; refresh responses cannot escalate an existing online grant.- token_auth_style
Registration type:
"public","header"for a symmetric secret using HTTP Basic, or"private_key_jwt". Selection must agree with advertised capabilities. Confidential methods must also agree with authentication metadata; public clients do not authenticate and need no"none"entry in that metadata. Later property edits must retain a supported SMART token authentication method. Asymmetric assertions requiretyp = "JWT", a key ID, an explicit RS384/ES384 algorithm, and the token endpoint as their audience.- client_secret
Secret for a symmetric registration; otherwise omit.
- client_assertion_private_key, client_assertion_private_key_kid
Private signing key and registered key ID for asymmetric authentication; see
oauth_client(). Required for"private_key_jwt".- client_assertion_alg
"RS384"(default) or"ES384"; the key and server metadata must support the selected algorithm. Other styles omit assertions."GET"(default) or"POST"for the outgoing browser request. POST requires the discoveredauthorize-postcapability and uses the module'srequest_login()orprepare_authorization_request(). POST supports longer browser requests but retains the scope comparison limits described underscopes.- response_mode
NULL,"query", or"form_post". Advertised response modes, when present, must allow the selection.See
oauth_client(). Multiple clients use distinct registered callback routes.- initial_expires_in_fallback
Optional positive lifetime in seconds, supplied by the authorization server out of band for initial access tokens. Used only when an initial response omits
expires_in; an explicit response value takes precedence. DefaultNULLrequires the response to include a lifetime.- label
Display label, default
"FHIR server".- state_store, state_key, state_payload_max_age
See
oauth_client().
Value
An OAuthClient for the module or connection manager. Its
resource_bases contains the approved fhir API; its smart property
records the selected profile.
Details
launch = "standalone" describes an app opened directly; "ehr" describes
one opened from an electronic health record. Each flow has its own app
registration. Patient context identifies the chart being viewed; identity
separately controls validation of the signed-in user. See
vignette("smart-on-fhir", package = "shinyOAuth")
(online guide)
for a complete app.
Advanced SMART profile
The constructor applies SMART App Launch 2.2 permission rules, S256 PKCE and
the exact FHIR base as the authorization request's aud. identity = "openid"
requires signed identity-token and nonce checks; "fhirUser" also requires
the user's FHIR reference.
Supported flows use direct authorization and query or form POST callbacks. Claims requests, remote authentication-freshness overrides, JAR, PAR, JARM, DPoP and mTLS are not supported by this constructor. The manager establishes a fresh registered transaction for each EHR launch; launch handles are single-use.
Tokens need a positive lifetime. Only an initial response may omit
expires_in, and only with an explicit initial_expires_in_fallback.
Refresh responses must supply a lifetime. Requests require TLS 1.2 or newer.
Examples
if (FALSE) { # \dontrun{
site <- smart_discover("https://ehr.example/fhir/R4")
client <- smart_client(site, "registered-app", "https://app.example/callback",
scopes = c("launch/patient", "patient/Patient.r"),
required_scopes = "patient/Patient.r", token_auth_style = "public")
client@smart[["launch"]]
} # }