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.
Ancestors
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.
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
expires : Optional[datetime.datetime]
- static
get_token : Callable[[], tuple[str, datetime.datetime]]
- 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,expiresmust also be provided.expires: Optional. Initial expiration time to use. If provided,jwtmust 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.
Ancestors
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).