Skip to main content

authentication

General authentication classes for external service interactions.

Module

Functions

build_ehr_jwt_session

def build_ehr_jwt_session(    *, ehr_secrets: SMARTBackendAuth | RefreshableJWT,)> RefreshableJWTSession:

Build a unified FHIR JWT session from SMART auth or external JWT secrets.

is_token_valid

def is_token_valid(expires: datetime)> bool:

Check if a token is still valid with a buffer before expiry.

smart_backend_handler_from_auth

def smart_backend_handler_from_auth(    smart_backend_auth: SMARTBackendAuth,)> RefreshableJWTHandler:

Build a generic JWT handler backed by SMART Backend auth token retrieval.

Classes

BearerAuthSession

class BearerAuthSession(bearer_token: str):

Session implementation that uses bearer authentication and auto-retry.

Has no notion of token expiration or (re)authentication, simply using the provided token as-is. If reauthentication is required, see RefreshableJWTSession.

Initializes a BearerAuthSession with the provided bearer token.

Methods


request

def request(    self,    method: str | bytes,    url: str | bytes,    params: Optional[MutableMapping[str, Any]] = None,    data: Any = None,    headers: Optional[MutableMapping[str, str]] = None,    **kwargs: Any,)> requests.models.Response:

Performs an HTTP request.

Overrides requests.session.request, appending our access token to the request headers or API keys if present.

JWT

class JWT(jwt: str, expires: datetime):

Thin container for JSON web token and its expiry.

Variables

  • static jwt : str

RefreshableJWT

class RefreshableJWT(    *,    jwt: Optional[str] = None,    expires: Optional[datetime] = None,    get_token: Callable[[], tuple[str, datetime]],):

Refreshable JWT.

A JWT that can be refreshed by calling the get_token callable. The get_token callable may raise (e.g. AuthenticationError) if the external source cannot provide a token; RefreshableJWTHandler will propagate that as AuthenticationError.

Variables

  • static jwt : Optional[str]

RefreshableJWTHandler

class RefreshableJWTHandler(    jwt: Optional[str],    expires: Optional[datetime],    get_token: Callable[[], tuple[str, datetime]],    **kwargs: Any,):

Authenticates user via JWT from an external source.

The Bitfount library hands responsibility for management of the token to the external source.

Whenever a new token is needed it makes a call to the get_token hook which provides one.

Creates a new instance of RefreshableJWTHandler.

Can be supplied an initial JWT and expiration time to use or ignore these and rely on the provided hook to get the first token.

Arguments

  • jwt: Optional. Initial JWT token to use. If provided, expires must also be provided.
  • expires: Optional. Initial expiration time to use. If provided, jwt must also be provided.
  • get_token: Callable that returns a tuple of a JWT and its expiration time.
  • **kwargs: Other kwargs to be passed to the superclass.

Subclasses

Variables

  • authenticated : bool - Whether the token is still valid.
  • jwt : Optional[str] - The JWT token.
  • request_headers : dict[str, typing.Any] - Header for authenticated requests.

    Checking that the call is authenticated is the responsibility of the calling code.

    Raises: AuthenticationError: If the JWT is not present or is expired.

Methods


authenticate

def authenticate(self, max_retries: int = 3, force: bool = False)> None:

Retrieves a token from the token source.

Calls the hook provided on object creation to retrieve a new token. Any exception from get_token (e.g. retrieval timeout, no credentials) is re-raised as AuthenticationError. Includes retry logic with exponential backoff for the case where the token source returns an expired token while refreshing.

Arguments

  • max_retries: Maximum number of retry attempts when the token source returns an expired token.
  • force: If True, discard the current token and fetch a fresh one regardless of whether the existing token appears valid. This is needed when the server rejects a token that has not yet expired (e.g. after a revocation or EHR reconnection).

Raises

  • AuthenticationError: If get_token raises or authentication fails after all retries.

get_valid_token

def get_valid_token(self, force: bool = False)> str:

Get a valid token to use.

Arguments

  • force: If True, discard the current token and fetch a fresh one even if the current token has not expired.

get_valid_token_with_expiry

def get_valid_token_with_expiry(    self, force: bool = False,)> tuple[str, datetime.datetime]:

Get a valid token and its expiry time.

Arguments

  • force: If True, discard the current token and fetch a fresh one even if the current token has not expired.

RefreshableJWTSession

class RefreshableJWTSession(authentication_handler: RefreshableJWTHandler):

Manages session-based interactions with authentication handled externally.

Extends requests.Session, appending an access token to the authorization of any requests made if an access token is present

When the token expires it will request a new token prior to sending the web request.

Variables

  • authenticated : bool - Returns true if we have an unexpired access token.
  • request_headers : dict[str, typing.Any] - Returns metadata for authenticating external service.

    Handles (re)authentication against the external service if needed.

Methods


authenticate

def authenticate(self)> None:

Authenticates session to allow protected requests.

request

def request(    self,    method: str | bytes,    url: str | bytes,    params: Optional[MutableMapping[str, Any]] = None,    data: Any = None,    headers: Optional[MutableMapping[str, str]] = None,    **kwargs: Any,)> requests.models.Response:

Performs an HTTP request.

Overrides requests.session.request, appending our access token to the request headers or API keys if present.

validate_token_via_introspection

def validate_token_via_introspection(    self, introspection_url: str, *, timeout: float = 10,)> Optional[bool]:

POST to an OAuth2 token introspection endpoint (RFC 7662).

OAuth overview: https://www.oauth.com/oauth2-servers/token-introspection-endpoint/

FHIR SMART: https://build.fhir.org/ig/HL7/smart-app-launch/token-introspection.html

Arguments

  • introspection_url: Introspection endpoint URL.
  • timeout: Request timeout in seconds.

Returns True if the token is active, False if the server reports inactive or authentication cannot be established, or None if the request failed (network, HTTP error, or invalid JSON).