cms-hte-ial2-reader
Reads IAL2 token, verifies digital signature and returns FHIR Patient resource
Accepts a signed JWT (ID Token) from a Credential Service Provider (CSP), verifies the signature via JWKS, extracts demographics per the CSP payload specification V7.1, and returns a FHIR R4 Patient resource.
Usage
from cmshteial2reader import IAL2Extractor, TokenVerifier
verifier = TokenVerifier(
jwks_uri="https://idp.example.com/.well-known/jwks.json",
audience="my-client-id",
)
extractor = IAL2Extractor(verifier=verifier)
patient = await extractor.extract(token_string)
# patient is a FHIR R4 Patient resource dict
To accept tokens from any issuer on an explicit allow list (rather than a
single pinned issuer), use MultiIssuerTokenVerifier in place of
TokenVerifier:
from cmshteial2reader import IAL2Extractor, MultiIssuerTokenVerifier
verifier = MultiIssuerTokenVerifier.from_env(audience="my-client-id")
extractor = IAL2Extractor(verifier=verifier)
patient = await extractor.extract(token_string)
MultiIssuerTokenVerifier.from_env reads its whitelist of trusted JWKS URLs
from the IAL2_ALLOWED_JWKS_URLS environment variable (comma-separated).
Assurance-level enforcement
IAL2Extractor requires the token's identity_assurance_level claim to be
at least IAL2 (accepting values like "ial2", "IAL2", or "2") -- a
token missing the claim, or asserting a lower level (e.g. "ial1"), raises
InsufficientAssuranceLevelError (a subclass of TokenVerificationError,
so existing callers that only catch the latter still catch this). This
applies to both extract() and extract_claims(). To require a higher
level, pass minimum_assurance_level to the constructor:
extractor = IAL2Extractor(verifier=verifier, minimum_assurance_level=3)
CMS Blue Button cms_smart extension
CMS Aligned Networks convey a patient's IAL2-verified identity by nesting a
CSP-issued ID token inside the outer auth token's claims, under
extensions.cms_smart.id_token (see
https://bluebutton.cms.gov/cms-aligned-networks-documentation/). Callers
that receive an already-verified outer JWT (e.g. from their own auth
middleware) can pull out the nested token with extract_cms_smart_id_token
and pass it to IAL2Extractor.extract:
from cmshteial2reader import IAL2Extractor, MultiIssuerTokenVerifier, extract_cms_smart_id_token
id_token = extract_cms_smart_id_token(outer_jwt_claims)
if id_token is not None:
verifier = MultiIssuerTokenVerifier.from_env(audience="my-client-id")
extractor = IAL2Extractor(verifier=verifier)
patient = await extractor.extract(id_token)
extract_cms_smart_id_token only reads the id_token claim -- it does not
verify anything, and it does not inspect or enforce purpose_of_use or
version. The outer JWT must already be signature-verified by the caller,
the nested id_token still needs its own verification via
IAL2Extractor/TokenVerifier, and a caller that needs to gate on
purpose-of-use must check claims["extensions"]["cms_smart"] itself.
Quickstart
make initto set up the local dev environment.make upto start the Docker dev stack.make teststo run tests in the dev container.
Common Tasks
make shellto open a shell in the dev container.make run-pre-committo run linting and formatting hooks.make buildto build the package artifacts.
Publishing
- Set a token:
export TWINE_PASSWORD=pypi-xxx make packageto publish to PyPI ormake testpackagefor TestPyPI.
Project Metadata
- Repo: https://github.com/icanbwell/cms-hte-ial2-reader
- Author: Imran Qureshi imran.qureshi@bwell.com
Metadata
Release files for cms-hte-ial2-reader 0.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cms_hte_ial2_reader-0.0.3.tar.gz | 26.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cms_hte_ial2_reader-0.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.8 kB
Release files / cms_hte_ial2_reader-0.0.3.tar.gz
| Download URL | cms_hte_ial2_reader-0.0.3.tar.gz |
|---|---|
| Size | 26.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2827baa1545bccf66fe2c6a85b6d2ce056d2ce9d5aab76852294506bd10bc108
|
|
BLAKE2b-256 checksum How to use checksums |
d716643f2fa3779bdb6d744ce1ec9d81c784e84863e7c5d97784bf81e6dea842
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / cms_hte_ial2_reader-0.0.3-py3-none-any.whl
| Download URL | cms_hte_ial2_reader-0.0.3-py3-none-any.whl |
|---|---|
| Size | 21.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8c1834fc5cba05bc127eba6e68f6949c03858f0ddf7f74382e28a0c066bb724f
|
|
BLAKE2b-256 checksum How to use checksums |
f6278f4315ca7a30c449345053d2444a4fbcbc1cbd14366d916449aef1fdba25
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency log