Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added quick_check.py
Empty file.
4 changes: 3 additions & 1 deletion src/supabase/src/supabase/_async/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions src/supabase/src/supabase/_sync/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
21 changes: 21 additions & 0 deletions src/supabase/tests/_sync/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Empty file added test_bug.py
Empty file.