Getting Started

This guide walks through connecting a third-party application to the Patient Access API using the SMART App Launch standalone flow with PKCE.

1 Register Your Application

Submit your application registration request. Once approved, you will receive a client_id that identifies your application in the authorization flow.

Register an Application
2 Discover the Authorization Endpoints

Fetch the SMART configuration document to discover all OAuth 2.0 endpoints. This document is updated automatically and should be fetched at application startup rather than hardcoded.

GET https://cms-api.wasatch.org/fhir/r4/.well-known/smart-configuration
Accept: application/json

The response includes the endpoints your application needs:

{
  "authorization_endpoint": "https://<authorization-server>/authorize",
  "token_endpoint":         "https://<authorization-server>/token",
  "scopes_supported":       ["openid", "fhirUser", "launch/patient", "patient/*.rs", ...],
  "capabilities":           ["launch-standalone", "client-public", "permission-patient", ...]
}

Use the authorization_endpoint and token_endpoint values returned by this document in the steps below — do not hardcode them. The capability statement is also available at https://cms-api.wasatch.org/fhir/r4/metadata.

3 Build the Authorization Request

Before redirecting the user, generate a PKCE code verifier and its SHA-256 challenge. PKCE is required — plain method is not supported.

// Pseudocode — generate PKCE values
code_verifier  = base64url(random_bytes(32))
code_challenge = base64url(sha256(ascii(code_verifier)))

Then redirect the user to the authorization_endpoint with these parameters:

GET {authorization_endpoint}
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https%3A%2F%2Fyourapp.example.com%2Fcallback
  &scope=openid%20fhirUser%20launch%2Fpatient%20patient%2F*.rs%20offline_access
  &state=RANDOM_UNGUESSABLE_VALUE
  &aud=https%3A%2F%2Fcms-api.wasatch.org%2Ffhir%2Fr4
  &code_challenge=BASE64URL_SHA256_OF_CODE_VERIFIER
  &code_challenge_method=S256

Parameter notes:

  • redirect_uri — Must exactly match one of the URIs you registered during application registration. Requests with an unregistered URI will be rejected.
  • scope — Space-separated list. See the Scopes Reference for all available values.
  • state — Must be a random, unguessable value. Validate it on the callback to prevent CSRF.
  • aud — The base URL of the FHIR server. Required by the SMART App Launch specification.
  • code_challenge_method — Only S256 is accepted.
4 Exchange the Authorization Code for a Token

After the user authorizes your application, they are redirected to your redirect_uri with a code query parameter. Exchange it for an access token by making a POST to the token endpoint:

POST {token_endpoint}
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTHORIZATION_CODE_FROM_CALLBACK
&redirect_uri=https%3A%2F%2Fyourapp.example.com%2Fcallback
&client_id=YOUR_CLIENT_ID
&code_verifier=CODE_VERIFIER_GENERATED_IN_STEP_3

A successful response returns:

{
  "access_token":  "eyJ...",
  "token_type":    "Bearer",
  "expires_in":    3600,
  "refresh_token": "0.A...",
  "id_token":      "eyJ...",
  "patient":       "123456",
  "scope":         "openid fhirUser launch/patient patient/*.rs offline_access"
}

Response field notes:

  • patient — The FHIR Patient ID of the authenticated patient. Use this value to construct patient-specific queries (e.g. /Patient/123456).
  • refresh_token — Only returned when offline_access is in the requested scope. See Step 5 for how to use it.
5 Refresh the Access Token

When the access_token expires, use the refresh_token to obtain a new one without prompting the patient again.

POST {token_endpoint}
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=REFRESH_TOKEN_FROM_STEP_4
&client_id=YOUR_CLIENT_ID

The response has the same shape as the authorization code token response and may include a rotated refresh_token — store it and discard the old one.

6 Make FHIR API Requests

Include the access token in the Authorization header on every FHIR request. All responses are returned as application/fhir+json.

GET https://cms-api.wasatch.org/fhir/r4/Patient/PATIENT_ID
Authorization: Bearer ACCESS_TOKEN
Accept: application/fhir+json

Use the patient value from the token response as PATIENT_ID. Resources are automatically scoped to that patient — no additional filtering is required.

Example paginated query:

GET https://cms-api.wasatch.org/fhir/r4/Condition?_count=20&_offset=0
Authorization: Bearer ACCESS_TOKEN
Accept: application/fhir+json

Error responses are returned as FHIR OperationOutcome resources:

{
  "resourceType": "OperationOutcome",
  "issue": [{
    "severity": "error",
    "code":     "forbidden",
    "diagnostics": "The requested scope is not authorized."
  }]
}
7 Direct Your Users to Register as a Patient

For patients to authorize your application to access their data, they must first be registered with Wasatch Behavioral Health. Direct your users to the Patient Registration page for instructions on completing in-person registration and linking their Microsoft EntraID account.

Register a Patient