99from fastmcp .server .auth .oauth_proxy import OAuthProxy
1010from fastmcp .server .auth import TokenVerifier
1111from mcp .server .auth .provider import AccessToken
12+ from key_value .aio .protocols import AsyncKeyValue
13+ from key_value .aio .wrappers .encryption import FernetEncryptionWrapper
14+ from cryptography .fernet import Fernet
15+ from fastmcp .server .auth .jwt_issuer import (
16+ derive_jwt_key ,
17+ )
1218
1319
1420class SingleStoreOAuthProxy :
@@ -36,6 +42,8 @@ def __init__(
3642 redirect_path : str | None = "/callback" ,
3743 valid_scopes : list [str ] | None = None ,
3844 jwt_signing_key : str | None = None ,
45+ client_storage : AsyncKeyValue | None = None ,
46+ encrypt_db : bool = True ,
3947 ):
4048 self .issuer_url = issuer_url
4149 # Assumes the default path for SingleStore's OpenID configuration
@@ -48,6 +56,8 @@ def __init__(
4856 self .redirect_path = redirect_path
4957 self .valid_scopes = valid_scopes or ["openid" ]
5058 self .jwt_signing_key = jwt_signing_key
59+ self .client_storage = client_storage
60+ self .encrypt_db = encrypt_db
5161
5262 # Fetch OpenID configuration
5363 self ._config = self ._fetch_openid_config ()
@@ -146,6 +156,17 @@ def _create_oauth_proxy(self) -> OAuthProxy:
146156 if not self .jwt_signing_key :
147157 raise RuntimeError ("JWT signing key is not set." )
148158
159+ parsed_client_storage = self .client_storage
160+ if self .client_storage and self .encrypt_db :
161+ storage_encryption_key = derive_jwt_key (
162+ high_entropy_material = self .jwt_signing_key ,
163+ salt = "fastmcp-storage-encryption-key" ,
164+ )
165+ # Wrap the client storage with encryption
166+ parsed_client_storage = FernetEncryptionWrapper (
167+ key_value = self .client_storage , fernet = Fernet (storage_encryption_key )
168+ )
169+
149170 return OAuthProxy (
150171 upstream_authorization_endpoint = authorization_endpoint ,
151172 upstream_token_endpoint = token_endpoint ,
@@ -156,6 +177,7 @@ def _create_oauth_proxy(self) -> OAuthProxy:
156177 redirect_path = self .redirect_path ,
157178 valid_scopes = self .valid_scopes ,
158179 jwt_signing_key = self .jwt_signing_key ,
180+ client_storage = parsed_client_storage ,
159181 )
160182
161183 def get_provider (self ) -> OAuthProxy :
0 commit comments