fix: add publishable_client_key parameter and fix token store defaults

- Add publishable_client_key param to BaseAPIClient, StackServerApp, AsyncStackServerApp
- Include x-stack-publishable-client-key header when key is provided
- Change ExplicitTokenStore defaults from empty string to None
- Remove empty string fallback in resolve_token_store dict branch
This commit is contained in:
Ejiro Asiuwhu
2026-03-25 07:51:38 +01:00
parent 6138ff0997
commit 09595481dd
3 changed files with 13 additions and 4 deletions
@@ -120,6 +120,7 @@ class StackServerApp:
*,
project_id: str,
secret_server_key: str,
publishable_client_key: str | None = None,
base_url: str = DEFAULT_BASE_URL,
token_store: TokenStoreInit | None = None,
) -> None:
@@ -127,6 +128,7 @@ class StackServerApp:
self._client = SyncAPIClient(
project_id=project_id,
secret_server_key=secret_server_key,
publishable_client_key=publishable_client_key,
base_url=base_url,
)
self._token_store: TokenStore | None = None
@@ -1397,6 +1399,7 @@ class AsyncStackServerApp:
*,
project_id: str,
secret_server_key: str,
publishable_client_key: str | None = None,
base_url: str = DEFAULT_BASE_URL,
token_store: TokenStoreInit | None = None,
) -> None:
@@ -1404,6 +1407,7 @@ class AsyncStackServerApp:
self._client = AsyncAPIClient(
project_id=project_id,
secret_server_key=secret_server_key,
publishable_client_key=publishable_client_key,
base_url=base_url,
)
self._token_store: TokenStore | None = None
@@ -38,10 +38,12 @@ class BaseAPIClient(Generic[HttpxClientT]):
base_url: str = DEFAULT_BASE_URL,
project_id: str,
secret_server_key: str,
publishable_client_key: str | None = None,
) -> None:
self._base_url = base_url.rstrip("/")
self._project_id = project_id
self._secret_server_key = secret_server_key
self._publishable_client_key = publishable_client_key
self._client: HttpxClientT | None = None
# ------------------------------------------------------------------
@@ -49,7 +51,7 @@ class BaseAPIClient(Generic[HttpxClientT]):
# ------------------------------------------------------------------
def _build_headers(self) -> dict[str, str]:
return {
headers = {
"x-stack-project-id": self._project_id,
"x-stack-access-type": "server",
"x-stack-secret-server-key": self._secret_server_key,
@@ -57,6 +59,9 @@ class BaseAPIClient(Generic[HttpxClientT]):
"x-stack-override-error-status": "true",
"x-stack-random-nonce": str(uuid.uuid4()),
}
if self._publishable_client_key is not None:
headers["x-stack-publishable-client-key"] = self._publishable_client_key
return headers
def _build_url(self, path: str) -> str:
return f"{self._base_url}/api/{API_VERSION}{path}"
@@ -97,7 +97,7 @@ class ExplicitTokenStore(TokenStore):
Supports CAS update to in-memory state to prevent infinite refresh loops.
"""
def __init__(self, access_token: str, refresh_token: str) -> None:
def __init__(self, access_token: str | None = None, refresh_token: str | None = None) -> None:
super().__init__()
self._access_token: str | None = access_token
self._refresh_token: str | None = refresh_token
@@ -194,8 +194,8 @@ def resolve_token_store(init: TokenStoreInit, project_id: str) -> TokenStore | N
return _get_or_create_memory_store(project_id)
if isinstance(init, dict):
return ExplicitTokenStore(
access_token=init.get("access_token", ""),
refresh_token=init.get("refresh_token", ""),
access_token=init.get("access_token"),
refresh_token=init.get("refresh_token"),
)
# Must be RequestLike (has .headers attribute)
return RequestTokenStore(init) # type: ignore[arg-type]