How to Integrate with EPIC EHR Using Python and SMART on FHIR APIs

Vinothkumar S

2 min read

Hey, HealthTech Builders!

In the rapidly evolving world of healthcare IT, the ability to securely access Electronic Health Records (EHRs) is a game-changer. EPIC, one of the most widely adopted EHR systems, offers this capability through SMART on FHIR APIs — enabling developers to build powerful applications around patient data.

In this guide, we’ll walk through how to integrate with EPIC using Python, leveraging OAuth 2.0’s Client Credentials flow to build a secure Backend Services App. This type of app is ideal for system-to-system communication where no user login is required.

📘 What You’ll Learn

  • How to register an app on the EPIC Developer Portal
  • Set up a simple Python backend project
  • Authenticate using JWT
  • Pull patient data from the EPIC FHIR API

✅ Step 1: Register Your App on the EPIC Developer Portal

Start by visiting the EPIC developer site: https://fhir.epic.com/

  1. Log in or create an account.
  2. Navigate to My Apps > Create New App.
  3. Select Backend Services App.
  4. Enter:
    • App Name
    • Description
    • FHIR API Version: R4
  5. Under Scopes, select:
    • system/Patient.read
  6. Upload your public key (explained in Step 2).
  7. Save the Client ID and FHIR base URL provided.

🔐 Step 2: Generate Your Key Pair

You’ll need a private-public RSA key pair to sign your JWT and authenticate with EPIC.

Run the following in your terminal:

bash

# Generate private key
openssl genrsa -out private_key.pem 2048

# Generate public key
openssl rsa -in private_key.pem -pubout -out public_key.pem

Upload public_key.pem to the EPIC Developer Portal.


Keep private_key.pem safe — this stays on your backend only.


🗂️ Step 3: Create Your Python Project Structure

Here’s a clean and minimal project setup:

epic_ehr_integration/
├── auth.py         # Handles authentication logic
├── fhir.py         # Fetches patient data
├── private_key.pem # Your private RSA key
├── main.py         # Entry point
└── requirements.txt

⚙️ Step 4: Set Up Python Environment

Create requirements.txt with the following dependencies:
nginx

requests
PyJWT
cryptography

Then install them:
bash
CopyEdit
pip install -r requirements.txt

Step 5: Authenticate Using JWT (auth.py)

# auth.py

import time
import jwt
import requests

CLIENT_ID = "your-epic-client-id"
TOKEN_URL = "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token"
PRIVATE_KEY_PATH = "private_key.pem"

def get_access_token():
    with open(PRIVATE_KEY_PATH, "r") as key_file:
        private_key = key_file.read()

    now = int(time.time())
    payload = {
        "iss": CLIENT_ID,
        "sub": CLIENT_ID,
        "aud": TOKEN_URL,
        "jti": str(now),
        "exp": now + 300  # Token valid for 5 minutes
    }

    jwt_token = jwt.encode(payload, private_key, algorithm="RS384")

    headers = { "Content-Type": "application/x-www-form-urlencoded" }
    data = {
        "grant_type": "client_credentials",
        "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": jwt_token,
        "scope": "system/Patient.read"
    }

    response = requests.post(TOKEN_URL, data=data, headers=headers)
    response.raise_for_status()
    return response.json()["access_token"]

📥 Step 6: Fetch Patient Data (fhir.py)

 # fhir.py

import requests

def get_patient_list(access_token, base_url):
    headers = {"Authorization": f"Bearer {access_token}"}
    url = f"{base_url}/Patient?_count=10"  # Retrieve 10 patients
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    return response.json()

▶️ Step 7: Run the Application (main.py)

# main.py

from auth import get_access_token
from fhir import get_patient_list

FHIR_BASE_URL = "https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4"

def main():
    token = get_access_token()
    patients = get_patient_list(token, FHIR_BASE_URL)

    for entry in patients.get("entry", []):
        patient = entry["resource"]
        name = patient.get("name", [{}])[0]
        full_name = f"{name.get('given', [''])[0]} {name.get('family', '')}"
        print(f"Patient ID: {patient['id']}, Name: {full_name}")

if __name__ == "__main__":
    main()

🧠 Conclusion

You now have a fully working Python backend integrated with EPIC’s FHIR API using secure OAuth 2.0 authentication. This setup allows you to fetch patient records programmatically — a powerful foundation for building EHR-connected healthcare apps.

You can extend this project to include:

  • Encounter details
  • Clinical notes
  • Lab results
  • Write-back functionality (with appropriate permissions)

Keeping the initial implementation simple ensures security and scalability as your app evolves. Whether you’re creating a clinical dashboard, analytics tool, or health monitoring service, this pattern is a proven, production-ready approach.

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *