Skip to content
Closed
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
3 changes: 1 addition & 2 deletions src/auth/src/supabase_auth/_async/gotrue_base_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def __init__(
verify: bool = True,
proxy: Optional[str] = None,
) -> None:
self._url = url
self._url = url.rstrip("/")
self._headers = headers
self._http_client = http_client or AsyncClient(
verify=bool(verify),
Expand Down Expand Up @@ -69,7 +69,6 @@ async def _request(
params=query,
json=model_dump(body) if isinstance(body, BaseModel) else body,
)

response.raise_for_status()
return response
except (HTTPStatusError, RuntimeError) as e:
Expand Down
3 changes: 1 addition & 2 deletions src/auth/src/supabase_auth/_sync/gotrue_base_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def __init__(
verify: bool = True,
proxy: Optional[str] = None,
) -> None:
self._url = url
self._url = url.rstrip("/")
self._headers = headers
self._http_client = http_client or Client(
verify=bool(verify),
Expand Down Expand Up @@ -69,7 +69,6 @@ def _request(
params=query,
json=model_dump(body) if isinstance(body, BaseModel) else body,
)

response.raise_for_status()
return response
except (HTTPStatusError, RuntimeError) as e:
Expand Down
26 changes: 26 additions & 0 deletions src/auth/tests/_async/test_gotrue.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,3 +797,29 @@ def handler(request: Request) -> Response:
assert Session.model_validate_json(stored).access_token == "new-access-token"
assert client._refresh_token_timer is not None
client._refresh_token_timer.cancel()


async def test_trailing_slash_in_url_does_not_produce_double_slash_paths() -> None:
from urllib.parse import urlsplit

from httpx import AsyncClient, MockTransport, Request, Response
from supabase_auth import AsyncGoTrueClient

requested_paths = []

def handler(request: Request) -> Response:
requested_paths.append(request.url.path)
return Response(200, json={})

client = AsyncGoTrueClient(
url="https://project.example/auth/v1/",
http_client=AsyncClient(transport=MockTransport(handler)),
)

# The OAuth authorize URL must not contain a doubled slash.
oauth_response = await client.sign_in_with_oauth({"provider": "github"})
assert urlsplit(oauth_response.url).path == "/auth/v1/authorize"

# Regular request paths must not contain a doubled slash either.
await client._request("GET", "user")
assert requested_paths == ["/auth/v1/user"]
26 changes: 26 additions & 0 deletions src/auth/tests/_sync/test_gotrue.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,3 +793,29 @@ def handler(request: Request) -> Response:
assert Session.model_validate_json(stored).access_token == "new-access-token"
assert client._refresh_token_timer is not None
client._refresh_token_timer.cancel()


def test_trailing_slash_in_url_does_not_produce_double_slash_paths() -> None:
from urllib.parse import urlsplit

from httpx import Client, MockTransport, Request, Response
from supabase_auth import SyncGoTrueClient

requested_paths = []

def handler(request: Request) -> Response:
requested_paths.append(request.url.path)
return Response(200, json={})

client = SyncGoTrueClient(
url="https://project.example/auth/v1/",
http_client=Client(transport=MockTransport(handler)),
)

# The OAuth authorize URL must not contain a doubled slash.
oauth_response = client.sign_in_with_oauth({"provider": "github"})
assert urlsplit(oauth_response.url).path == "/auth/v1/authorize"

# Regular request paths must not contain a doubled slash either.
client._request("GET", "user")
assert requested_paths == ["/auth/v1/user"]