diff --git a/quick_check.py b/quick_check.py new file mode 100644 index 00000000..e69de29b diff --git a/src/supabase/src/supabase/_async/client.py b/src/supabase/src/supabase/_async/client.py index 8b81e6ed..a43885b1 100644 --- a/src/supabase/src/supabase/_async/client.py +++ b/src/supabase/src/supabase/_async/client.py @@ -97,6 +97,7 @@ def __init__( self._postgrest: Optional[AsyncPostgrestClient] = None self._storage: Optional[AsyncStorageClient] = None self._functions: Optional[AsyncFunctionsClient] = None + self.auth.admin._headers = {**self.auth.admin._headers} self.auth.on_auth_state_change(self._listen_to_auth_events) @classmethod @@ -342,12 +343,13 @@ def _listen_to_auth_events( self._storage = None self._functions = None access_token = session.access_token if session else self.supabase_key + auth_header = self._create_auth_header(access_token) self.options.headers["Authorization"] = auth_header self.auth._headers["Authorization"] = auth_header + self.auth.admin._headers["Authorization"] = self._create_auth_header(self.supabase_key) asyncio.create_task(self.realtime.set_auth(access_token)) - async def create_client( supabase_url: str, supabase_key: str, diff --git a/src/supabase/src/supabase/_sync/client.py b/src/supabase/src/supabase/_sync/client.py index 29c0246b..9f81dcc7 100644 --- a/src/supabase/src/supabase/_sync/client.py +++ b/src/supabase/src/supabase/_sync/client.py @@ -96,6 +96,7 @@ def __init__( self._postgrest: Optional[SyncPostgrestClient] = None self._storage: Optional[SyncStorageClient] = None self._functions: Optional[SyncFunctionsClient] = None + self.auth.admin._headers = {**self.auth.admin._headers} self.auth.on_auth_state_change(self._listen_to_auth_events) @classmethod @@ -344,6 +345,7 @@ def _listen_to_auth_events( auth_header = self._create_auth_header(access_token) self.options.headers["Authorization"] = auth_header self.auth._headers["Authorization"] = auth_header + self.auth.admin._headers["Authorization"] = self._create_auth_header(self.supabase_key) def create_client( diff --git a/src/supabase/tests/_sync/test_client.py b/src/supabase/tests/_sync/test_client.py index a490d67d..ba60a881 100644 --- a/src/supabase/tests/_sync/test_client.py +++ b/src/supabase/tests/_sync/test_client.py @@ -282,3 +282,24 @@ def test_httpx_client_base_url_isolation() -> None: assert str(postgrest.base_url).rstrip("/").endswith("/rest/v1"), ( "PostgREST base_url was mutated after accessing functions" ) + +def test_admin_authorization_header_not_overwritten_on_auth_events() -> None: + """Admin API should always use the supabase_key, never the user session token. + Regression test for https://github.com/supabase/supabase-py/issues/1404 + """ + url = os.environ["SUPABASE_TEST_URL"] + key = os.environ["SUPABASE_TEST_KEY"] + + client = create_client(url, key) + + mock_session = MagicMock(access_token="secretuserjwt") + realtime_mock = Mock() + client.realtime = realtime_mock + + client._listen_to_auth_events("SIGNED_IN", mock_session) + + # auth._headers should have the user token (existing behaviour) + assert client.auth._headers.get("Authorization") == "Bearer secretuserjwt" + + # admin._headers must always keep the original supabase_key + assert client.auth.admin._headers.get("Authorization") == f"Bearer {key}" diff --git a/test_bug.py b/test_bug.py new file mode 100644 index 00000000..e69de29b