Description
Describe the feature
Extend JWTAuthentication
to support both static JWT tokens and JWT tokens dynamically produced by given Callable objects.
This extension aims to refresh JWT tokens in JWTAuthentication
.
Context
We are currently trying to use JWT access tokens issued by Azure Entra ID (aka. Azure Active Directory) to authenticate clients (more precisely, DBT workflows running in Azure) accessing our Trino.
Retrieving access tokens from Entra ID is a straightforward process. We can accomplish this by using the TokenCredential
implementations provided by the azure-identity
package. For instance,
### "api://..." is the application URI of our Trino registered in Entra ID -> will appear as "aud" in JWT tokens.
scope = "api://xxxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxx/.default"
credential = DefaultAzureCredential()
jwt_token = credential.get_token(scope).token
conn = connect(
auth=JWTAuthentication(jwt_token)
http_scheme="https",
...
)
A problem here is that there is no way to refresh tokens set to JWTAuthentication
as the current version of JWTAuthentication
accepts only a static token, and sets the token to requests.Session
objects as a static auth header value.
For example, JWT tokens issued by Entra ID usually expire within 1 hour or less. Therefore, an application using JWTAuthentication
will fail at a certain moment due to the expiration of access tokens unless the application frequently recreates the JWTAuthentication
instance with a new token.
Proposal
Extend JWTAuthentication
to accept both a static JWT token and a Callable
object as the init argument.
https://github.com/trinodb/trino-python-client/blob/0.328.0/trino/auth.py#L146-L153
class JWTAuthentication(Authentication):
def __init__(self, token: Union[str, Callable[[], str]]):
if isinstance(token, str):
self.token_provider = lambda : token
else:
self.token_provider = token
def set_http_session(self, http_session: Session) -> Session:
http_session.auth = _BearerAuth(self.token_provider)
return http_session
We also need to extend _BearerAuth
.
https://github.com/trinodb/trino-python-client/blob/0.328.0/trino/auth.py#L142
r.headers["Authorization"] = "Bearer " + self.token_provider()
With this extension, we can rewrite the sample code above as follows:
conn = connect(
auth=JWTAuthentication(lambda: credential.get_token(scope).token)
http_scheme="https",
...
)
This code won't fail as the credential
(DefaultAzureCredential
) will automatically cache and refresh access tokens.
Describe alternatives you've considered
We have implemented a custom JWTAuthentication
with this extension by ourselves. However, JWT token refresh is a common concern that can appear in various use case scenarios. It would be nice to have this extension as a part of the Trino Python client.
Are you willing to submit PR?
- Yes I am willing to submit a PR!