- Descritpion
- Installation
- Configuration
- Usages: Obtain Access Grant, Probe Scope, and Access Data
- A Complete Sample App
- API Versions and Environments
- SDK Development
This is an SDK for interacting with the CMS Blue Button 2.0 API. The API allows applications to obtain a beneficiary's (who has login account with medicare.gov) grant to access their medicare claims data - through the OAuth 2.0 (RFC 6749) authorization flow.
By using the SDK, the development of applications accessing the Blue Button 2.0 API can be greatly simplified.
Note: In following OAuth 2.0 best practices, the PKCE extension (RFC 7636) is always enabled.
$ pip install cms-bluebutton-sdkThe SDK needs to be properly configured to work.
The configuration parameters are:
- The app's credentials - client id, client secret
- The app's callback url
- The version number of the API
- The app's environment (the BB2.0 web location where the app is registered)
- The FHIR call retry settings
- Enable / Disable Token refresh if FHIR request processing detected the access token expired
| Parameter | Value | Comments |
|---|---|---|
| environment | "SANDBOX" or "PRODUCTION" | BB2 API environment (default="SANDBOX") |
| version | 1 or 2 | BB2 API version (default=2) |
| client_id | "foo" | oauth2 client id of the app |
| client_secret | "bar" | oauth2 client secret of the app |
| callback_url | "https://www.fake.com/callback" | oauth2 callback URL of the app |
For application registration and client id and client secret, please refer to: Blue Button 2.0 API Docs - Try the API
Auth Token Refresh on Expire:
SDK FHIR requests will check if the access token is expired before the data end point call, if the access token is expired, then a token refresh is performed with the refresh token in the current auth token object, this behavior can be disabled by setting configuration parameter as below:
"token_refresh_on_expire": false
By default, token_refresh_on_expire is true.
FHIR requests retry:
Retry is enabled by default for FHIR requests, retry_settings: parameters for exponential back off retry algorithm
| retry parameter | value (default) | Comments |
|---|---|---|
| backoff_factor | 5 | back off factor in seconds |
| total | 3 | max retries |
| status_forcelist | [500, 502, 503, 504] | error response codes to retry on |
the exponential back off factor (in seconds) is used to calculate interval between retries by below formular, where i starts from 0:
backoff factor * (2 ** (i - 1))
e.g. for backoff_factor is 5 seconds, it will generate wait intervals: 2.5, 5, 10, ...
to disable the retry: set total = 0
There are three ways to configure the SDK when instantiating a BlueButton class instance:
-
Python Dictionary:
- A dictionary of configuration key:value pairs can be used.
- Configuration values can be provided from your own application's configuration method.
- Example code:
bb = BlueButton({ "environment": "PRODUCTION", "client_id": "foo", "client_secret": "bar", "callback_url": "https://www.fake.com/callback", "version": 2, "retry_settings": { "total": 3, "backoff_factor": 5, "status_forcelist": [500, 502, 503, 504] } }
-
JSON config file:
- This is using a configuration file that is in a JSON format.
- This is stored in a local file.
- The default location is in the current working directory with a file name: .bluebutton-config.json
- Example code:
bb = BlueButton("settings/my_bb2_sdk_conf.json")
- Example JSON in file:
{ "environment": "SANDBOX", "client_id": "foo", "client_secret": "bar", "callback_url": "https://www.fake.com/callback", "version": 2, "retry_settings": { "total": 3, "backoff_factor": 5, "status_forcelist": [500, 502, 503, 504] } }
-
YAML config file:
- This is using a configuration file that is in a YAML format.
- This is stored in a local file.
- The default location is in the current working directory with a file name: .bluebutton-config.yaml
- Example code:
bb = BlueButton("settings/my_bb2_sdk_conf.yaml")
- Example YAML in file:
environment: "SANDBOX" client_id: "foo" client_secret: "bar" callback_url: "https://www.fake.com/callback" version: 2
Below are psuedo code snippets showing SDK used with python server and flask.
from flask import Flask
from flask import redirect, request
from cms_bluebutton import BlueButton, AuthorizationToken
# initialize the app
app = Flask(__name__)
# Instantiate SDK class instance via conf in file
bb = BlueButton()
# auth_data is saved for the current user
auth_data = bb.generate_auth_data()
"""
AuthorizationToken holds access grant info:
access token, expire in, expire at, token type, scope, refreh token, etc.
It is associated with current logged in user in real app.
Check SDK python docs for more details.
"""
auth_token = None
# Start authorize flow: Response with URL to redirect to Medicare.gov beneficiary login
@app.route("/", methods=["GET"])
def get_auth_url():
return bb.generate_authorize_url(auth_data)
@app.route('/api/bluebutton/callback/', methods=['GET'])
def authorization_callback():
request_query = request.args
code = request_query.get('code')
state = request_query.get('state')
auth_token = bb.get_authorization_token(auth_data, code, state)
"""
Now access token obtained.
Note: During authorization, the beneficiary can grant
access to their demographic data and claims data or only claims data.
Check the scope
of the current access token as shown below:
"""
scopes = auth_token.scope
# iterate scope entries here or check if a permission is in the scope
if "patient/Patient.read" in scopes:
# patient info access granted
"""
1. access token scope where demagraphic info included:
scope: [
"patient/Coverage.read",
"patient/ExplanationOfBenefit.read",
"patient/Patient.read",
"profile",
]
2. access token scope where demagraphic info not included:
scope: [
"patient/Coverage.read",
"patient/ExplanationOfBenefit.read",
]
"""
config = {
"auth_token": auth_token,
"params": {},
"url": "to be overriden"
}
result = {}
# fetch eob, patient, coverage, profile
try:
eob_data = bb.get_explaination_of_benefit_data(config)
result['eob_data'] = eob_data['response'].json()
eob_data = eob_data['response'].json()
result['eob_data'] = eob_data
# fhir search response can contain large number of resources,
# e.g. it is not unusual an EOB search of a beneficiary would result
# in hundreds of EOB resources, by default they are chunked into pages
# of 10 resources each, e.g. the above call bb.get_explaination_of_benefit_data(config)
# return the 1st page of EOBs, in the format of a FHIR bundle resource
# with a link section where page navigation urls with the link name as:
# 'first', 'last', 'self', 'next', 'previous', which indicating the
# pagination relation relative to the current page.
# Use bb.get_pages(data, config) to get all the pages
eob_pages = bb.get_pages(eob_data, config)
result['eob_pages'] = eob_pages['pages']
auth_token = eob_pages['auth_token']
pt_data = bb.get_patient_data(config)
result['patient_data'] = pt_data['response'].json()
coverage_data = bb.get_coverage_data(config)
result['coverage_data'] = coverage_data['response'].json()
profile_data = bb.get_profile_data(config)
result['profile_data'] = profile_data['response'].json()
except Exception as ex:
print(ex)
return result
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=3001)A Python React sample app can be found at: CMS Blue Button Python Sample App
Can be selected for environments: PRODUCTION and SANDBOX.
The Blue Button API is available in versions v1 and v2.
The data served from v1 is in FHIR STU2 format, and data from v2 is in FHIR R4 format.
An application's target environment and API version can be set in the SDK configuration as shown by the JSON example below:
{
"clientId": "foo",
"clientSecret": "bar",
"callbackUrl": "https://www.fake.com/",
"version": "2",
"environment": "PRODUCTION"
}If not included, the default API version is v2, and the default environment is SANDBOX.
Web location of the environments:
PRODUCTION Environment: https://api.bluebutton.cms.gov
SANDBOX Environment: https://sandbox.bluebutton.cms.gov
Documentation for BB2 team members and others developing the SDK can be found here: README-sdk-dev.md