[docs]classIDTokenDecoder:""" JWT decoder for OIDC ID tokens issued by Globus Auth. Decoding uses a client object to fetch necessary data from Globus Auth. By default, the OIDC configuration data and JWKs will be cached in an internal dict. An alternative cache can be provided on init to use an alternative storage mechanism. The ``get_jwt_audience`` and ``get_jwt_leeway`` methods supply parameters to decoding. Subclasses can override these methods to customize the decoder. :param auth_client: The client which should be used to callout to Globus Auth as needed. Any AuthClient or AuthLoginClient will work for this purpose. :param jwt_leeway: The JWT leeway to use during decoding, as a number of seconds or a timedelta. The default is 5 minutes. :param jwt_options: The ``options`` passed to the underlying JWT decode function. Defaults to an empty dict. """def__init__(self,auth_client:SupportsJWKMethods,*,# default to 300 seconds## valuable inputs to this number:# - expected clock drift per day (6s for a bad clock)# - Windows time sync interval (64s)# - Windows' stated goal of meeting the Kerberos 5 clock skew requirement (5m)# - ntp panic threshold (1000s of drift)# - the knowledge that VM clocks typically run slower and may skew significantly## NTP panic should be understood as a critical error; 1000s of drift is# therefore too high for us to allow.## 300s (5m) is therefore chosen to match the Windows desired maximum for# clock drift, and the underlying Kerberos requirement.jwt_leeway:float|datetime.timedelta=300.0,jwt_options:dict[str,t.Any]|None=None,)->None:self._auth_client=auth_clientself._openid_configuration:dict[str,t.Any]|None=Noneself._jwk:RSAPublicKey|None=Noneself.jwt_leeway:float|datetime.timedelta=jwt_leewayself.jwt_options:dict[str,t.Any]=(jwt_optionsifjwt_optionsisnotNoneelse{})@classmethoddeffor_globus_app(cls,*,app_name:str,# pylint: disable=unused-argumentconfig:GlobusAppConfig,# pylint: disable=unused-argumentlogin_client:AuthLoginClient,)->Self:""" Create an ``IDTokenDecoder`` for use in a GlobusApp. :param app_name: The name supplied to the GlobusApp. :param config: The configuration supplied to the GlobusApp. :param login_client: A login client to use for instantiating an ``IDTokenDecoder``. """returncls(login_client)defdecode(self,id_token:str,/)->dict[str,t.Any]:""" The ``decode()`` method takes an ``id_token`` as a string, and decodes it to a dictionary. This method should implicitly retrieve the OpenID configuration and JWK for Globus Auth. :param id_token: The token to decode """audience=self.get_jwt_audience()openid_configuration=self.get_openid_configuration()jwk=self.get_jwk()signing_algos=openid_configuration["id_token_signing_alg_values_supported"]returnjwt.decode(id_token,key=jwk,algorithms=signing_algos,audience=audience,options=self.jwt_options,leeway=self.jwt_leeway,)defget_jwt_audience(self)->str|None:""" The audience for JWT verification defaults to the client's client ID. """returnself._auth_client.client_iddefstore_openid_configuration(self,openid_configuration:dict[str,t.Any]|GlobusHTTPResponse)->None:""" Store openid_configuration data for future use in ``decode()``. :param openid_configuration: The configuration data, as fetched via :meth:`AuthClient.get_openid_configuration` """ifisinstance(openid_configuration,GlobusHTTPResponse):self._openid_configuration=openid_configuration.dataelse:self._openid_configuration=openid_configurationdefstore_jwk(self,jwk:RSAPublicKey)->None:""" Store a JWK for future use in ``decode()``. :param jwk: The JWK, as fetched via :meth:`AuthClient.get_jwk` with ``as_pem=True``. """self._jwk=jwkdefget_openid_configuration(self)->dict[str,t.Any]:""" Fetch the OpenID Configuration for Globus Auth, and cache the result before returning it. If a config was previously stored, return that instead. """ifself._openid_configurationisNone:self._openid_configuration=(self._auth_client.get_openid_configuration().data)returnself._openid_configurationdefget_jwk(self)->RSAPublicKey:""" Fetch the JWK for Globus Auth, and cache the result before returning it. If a key was previously stored, return that instead. """ifnotself._jwk:self._jwk=self._auth_client.get_jwk(openid_configuration=self.get_openid_configuration(),as_pem=True)returnself._jwk