66import json
77from dataclasses import InitVar , dataclass
88from datetime import datetime
9- from typing import Any , Mapping , Optional , Union , cast
9+ from typing import Any , Mapping , MutableMapping , Optional , Union , cast
1010
1111import jwt
1212from cryptography .hazmat .primitives import serialization
1313from cryptography .hazmat .primitives .asymmetric .ec import EllipticCurvePrivateKey
1414from cryptography .hazmat .primitives .asymmetric .ed448 import Ed448PrivateKey
1515from cryptography .hazmat .primitives .asymmetric .ed25519 import Ed25519PrivateKey
1616from cryptography .hazmat .primitives .asymmetric .rsa import RSAPrivateKey
17- from cryptography .hazmat .primitives .asymmetric .types import PrivateKeyTypes
1817
1918from airbyte_cdk .sources .declarative .auth .declarative_authenticator import DeclarativeAuthenticator
2019from airbyte_cdk .sources .declarative .interpolation .interpolated_boolean import InterpolatedBoolean
2120from airbyte_cdk .sources .declarative .interpolation .interpolated_mapping import InterpolatedMapping
2221from airbyte_cdk .sources .declarative .interpolation .interpolated_string import InterpolatedString
22+ from airbyte_cdk .sources .declarative .requesters .request_option import (
23+ RequestOption ,
24+ RequestOptionType ,
25+ )
2326
2427# Type alias for keys that JWT library accepts
2528JwtKeyTypes = Union [
@@ -86,6 +89,7 @@ class JwtAuthenticator(DeclarativeAuthenticator):
8689 additional_jwt_headers : Optional [Mapping [str , Any ]] = None
8790 additional_jwt_payload : Optional [Mapping [str , Any ]] = None
8891 passphrase : Optional [Union [InterpolatedString , str ]] = None
92+ request_option : Optional [RequestOption ] = None
8993
9094 def __post_init__ (self , parameters : Mapping [str , Any ]) -> None :
9195 self ._secret_key = InterpolatedString .create (self .secret_key , parameters = parameters )
@@ -121,6 +125,13 @@ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
121125 else None
122126 )
123127
128+ # When we first implemented the JWT authenticator, we assumed that the signed token was always supposed
129+ # to be loaded into the request headers under the `Authorization` key. This is not always the case, but
130+ # this default option allows for backwards compatibility to be retained for existing connectors
131+ self ._request_option = self .request_option or RequestOption (
132+ inject_into = RequestOptionType .header , field_name = "Authorization" , parameters = parameters
133+ )
134+
124135 def _get_jwt_headers (self ) -> dict [str , Any ]:
125136 """
126137 Builds and returns the headers used when signing the JWT.
@@ -213,7 +224,8 @@ def _get_header_prefix(self) -> Union[str, None]:
213224
214225 @property
215226 def auth_header (self ) -> str :
216- return "Authorization"
227+ options = self ._get_request_options (RequestOptionType .header )
228+ return next (iter (options .keys ()), "" )
217229
218230 @property
219231 def token (self ) -> str :
@@ -222,3 +234,18 @@ def token(self) -> str:
222234 if self ._get_header_prefix ()
223235 else self ._get_signed_token ()
224236 )
237+
238+ def get_request_params (self ) -> Mapping [str , Any ]:
239+ return self ._get_request_options (RequestOptionType .request_parameter )
240+
241+ def get_request_body_data (self ) -> Union [Mapping [str , Any ], str ]:
242+ return self ._get_request_options (RequestOptionType .body_data )
243+
244+ def get_request_body_json (self ) -> Mapping [str , Any ]:
245+ return self ._get_request_options (RequestOptionType .body_json )
246+
247+ def _get_request_options (self , option_type : RequestOptionType ) -> Mapping [str , Any ]:
248+ options : MutableMapping [str , Any ] = {}
249+ if self ._request_option .inject_into == option_type :
250+ self ._request_option .inject_into_request (options , self .token , self .config )
251+ return options
0 commit comments