Credential Caching with Keyring
flyte-sdk provides an automatic credential caching mechanism that leverages the system's native keyring to store and retrieve authentication tokens. This ensures that once a user or service has authenticated with a Flyte endpoint, subsequent requests can reuse the cached tokens without requiring repeated manual logins or re-authentication flows.
Credential Representation
The Credentials class in remote._client.auth._keyring is a Pydantic model that encapsulates the tokens required for authentication. It stores the access_token, an optional refresh_token, and the specific for_endpoint the credentials belong to.
To ensure uniqueness and facilitate tracking, the class automatically computes an id field by hashing the access_token using MD5:
# From remote/_client/auth/_keyring.py
@pydantic.model_validator(mode="after")
def compute_id(self) -> "Credentials":
"""Computes the id field as a hash of the access_token."""
if self.access_token:
self.id = hashlib.md5(self.access_token.encode()).hexdigest()
return self
The for_endpoint field is also normalized using the strip_scheme function, which removes protocols like https:// or dns:/// to create a consistent service name for the keyring backend.
The Keyring Store
The KeyringStore class provides static methods to interact with the system keyring. It acts as a bridge between flyte-sdk and the keyring library, handling the storage, retrieval, and deletion of tokens.
Storage and Retrieval
When credentials are saved, the KeyringStore.store method uses the normalized endpoint as the "service" name and predefined keys (access_token and refresh_token) as the "usernames" in the keyring:
# From remote/_client/auth/_keyring.py
@staticmethod
def store(credentials: Credentials) -> Credentials:
try:
if credentials.refresh_token:
keyring.set_password(
credentials.for_endpoint,
KeyringStore._refresh_token_key,
credentials.refresh_token,
)
keyring.set_password(
credentials.for_endpoint,
KeyringStore._access_token_key,
credentials.access_token,
)
except NoKeyringError as e:
logger.debug(f"KeyRing not available, tokens will not be cached. Error: {e}")
return credentials
Retrieval via KeyringStore.retrieve(endpoint) attempts to reconstruct a Credentials object from these stored values. If the access_token is missing or the keyring backend is unavailable, it returns None, signaling that a fresh authentication flow is required.
Cache Invalidation
To prevent the use of stale or invalid tokens, the KeyringStore.delete method removes both the access and refresh tokens for a specific endpoint. This is typically triggered when an authentication refresh fails, ensuring the local cache does not contain broken credentials.
Integration with Authenticators
Credential caching is integrated directly into the base Authenticator class in remote._client.auth._authenticators.base. The caching logic is largely transparent to the user:
- Initialization: When an
Authenticatoris created, it automatically attempts to load credentials from the keyring if none are explicitly provided:
# From remote/_client/auth/_authenticators/base.py
self._creds = credentials or KeyringStore.retrieve(endpoint)
- Automatic Updates: After a successful credential refresh (e.g., using a refresh token to get a new access token), the
Authenticatorupdates the local cache:
# From remote/_client/auth/_authenticators/base.py
try:
self._creds = await self._do_refresh_credentials()
KeyringStore.store(self._creds)
except Exception:
KeyringStore.delete(self._endpoint)
raise
Implementation Considerations
Silent Failures
The keyring functionality is designed to be non-intrusive. If the keyring library is not installed or if the system does not have a configured keyring backend (common in headless CI/CD environments), flyte-sdk logs a debug message and continues without caching. It does not raise exceptions for missing keyring support, ensuring that authentication still works even if caching is unavailable.
Internal Scope
The remote._client.auth._keyring package is considered internal. While it manages sensitive tokens, it relies on the security of the underlying operating system's keyring (such as macOS Keychain, Windows Credential Locker, or Secret Service on Linux). Developers should generally interact with authentication through the Authenticator subclasses rather than calling KeyringStore methods directly.