Review the SMART App Launch IG Backend Services section (hl7.org/fhir/smart-app-launch) to understand the client credentials flow using asymmetric JWT authentication.
Generate an RSA or EC key pair for the backend service; register the public key (or JWKS URL) with the FHIR authorization server out-of-band (typically via a payer portal or API management system).
Construct a JWT client assertion: set iss and sub to the registered client_id, aud to the authorization server's token endpoint URL, exp to a short future timestamp (e.g., 5 minutes), and jti to a unique nonce; sign with the private key.
POST the token request to the authorization server's token endpoint with grant_type=client_credentials, client_assertion_type of urn:ietf:params:oauth:client-assertion-type:jwt-bearer, client_assertion set to the signed JWT, and scope set to the required system-level scopes (e.g., system/Patient.read, system/ExplanationOfBenefit.read).
Receive the access token response; extract the access_token and expires_in values; store the token and implement proactive refresh before expiry.
Use the access token as a Bearer token in the Authorization header of all FHIR Bulk Data requests; handle 401 responses by refreshing the token rather than surfacing an authentication error to the application layer.
Known gotchas
The JWT jti (JWT ID) claim must be unique per token request — reusing a jti value will cause the authorization server to reject the request as a replay attack; use a UUID or similarly collision-resistant identifier.
System-level scopes for bulk data use the 'system/' prefix, not 'patient/' or 'user/' — requesting the wrong scope prefix will result in a scope rejection even if the application has been authorized for the resource type.
Some payers require the JWKS URL to be HTTPS and publicly reachable at token request time — a JWKS URL that is behind a firewall or uses a self-signed certificate will fail JWKS resolution and cause all token requests to fail.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp