Skip to main content

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, and returns a FHIR R4 Patient resource. Transparently accepts three token shapes, with no caller-facing difference in usage:

  • CMS-Aligned Networks CSP Payload Specification V7.1 -- flat claims.
  • TEFCA IAS SOP v3.0 -- flat claims with a different field-name vocabulary (e.g. regionality instead of region); a token missing the identity_assurance_level claim is treated as implicit IAL2 if it looks TEFCA-shaped, since the SOP guarantees IAL2 proofing as a precondition of the CSP issuing the token at all.
  • Unified Identity Token Payload (OIDC4IDA-style) -- the CMS-Aligned Networks / TEFCA working group's in-progress target format, nesting verified attributes in a verified_claims.{verification,claims} envelope. This is a discussion draft, not a finalized spec.

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)

A TEFCA-dialect token (one with no identity_assurance_level claim but recognizable TEFCA-only fields such as regionality/historical_address/ ssn_last_four_digits) is only treated as implicit IAL2 -- never a higher level, since that's all the SOP guarantees -- and only after the token has already passed signature verification (and, for MultiIssuerTokenVerifier, issuer whitelisting). Raising minimum_assurance_level above 2 will reject TEFCA-dialect tokens, since they can't assert anything higher.

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

  • Copy .env.example to .env and fill in your JFrog credentials (get a token from https://artifacts.bwell.com/ -> Edit Profile -> Identity Tokens); also export JFROG_READ_USER/JFROG_READ_TOKEN in your shell -- Docker builds read them as BuildKit secrets, not from .env.
  • make init to set up the local dev environment.
  • make up to start the Docker dev stack.
  • make tests to run tests in the dev container.

Common Tasks

  • make shell to open a shell in the dev container.
  • make run-pre-commit to run linting and formatting hooks.
  • make build to build the package artifacts.

Publishing

  • Set a token: export TWINE_PASSWORD=pypi-xxx
  • make package to publish to PyPI or make testpackage for TestPyPI.

Project Metadata

Metadata

Release files for cms-hte-ial2-reader 0.0.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cms-hte-ial2-reader 0.0.5
File Size Uploaded
cms_hte_ial2_reader-0.0.5.tar.gz 33.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cms-hte-ial2-reader 0.0.5
File Interpreter ABI Platform
cms_hte_ial2_reader-0.0.5-py3-none-any.whl Python 3 none any Details

Total release size: 58.8 kB

Release files / cms_hte_ial2_reader-0.0.5.tar.gz

Download URL cms_hte_ial2_reader-0.0.5.tar.gz
Size 33.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d6b5c6830aeea24e0495567d3d81e223d26f1e8feaa7f5527e29514a6faf7deb
BLAKE2b-256 checksum
How to use checksums
e1109709af8d5e7584b5e213c7135ff4dd694d265b83bcf56566c09b3a28e940
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 Oct 7, 2026.

Transparency log

Release files / cms_hte_ial2_reader-0.0.5-py3-none-any.whl

Download URL cms_hte_ial2_reader-0.0.5-py3-none-any.whl
Size 25.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a459db6b82b1dfb040f93535aeeb8b41e2c301fe988e9fbb622115d3a10864df
BLAKE2b-256 checksum
How to use checksums
8ffa07772302e9f9f4a9350f0dce5f716b10d5c6a2b16cf9081b34419d173920
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 Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.5 This release

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page