Skip to content
Merged
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
16 changes: 15 additions & 1 deletion agentscore_commerce/checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,20 @@ def _spec_method_name(spec: CheckoutRailSpec) -> str:
return "stripe/spt" # StripeRailSpec is the only remaining variant in CheckoutRailSpec.


def _realm_from_url(url: str) -> str:
"""Derive the WWW-Authenticate ``realm`` from the checkout endpoint URL.

The realm identifies the protection space and, by convention (and to match the Node
SDK, which passes ``new URL(APP_URL).host``), is the bare host, not the full endpoint
URL. ``Checkout(url="https://agents.example.com/purchase")`` yields realm
``agents.example.com``. Falls back to the input unchanged when it has no parseable host
(e.g. already a bare host, or a relative path).
"""
from urllib.parse import urlparse

return urlparse(url).netloc or url


@dataclass
class CheckoutRequest:
"""Framework-neutral HTTP request input to :meth:`Checkout.handle`.
Expand Down Expand Up @@ -907,7 +921,7 @@ def __init__(
getter = lazy_mppx_server(
rails=mpp_rails,
secret_key=mppx_secret_key,
realm=url,
realm=_realm_from_url(url),
)
compose_mppx = make_mppx_compose_hook(server_getter=getter)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "agentscore-commerce"
version = "2.5.10"
version = "2.5.11"
description = "Agent commerce SDK for Python — identity middleware (FastAPI, Flask, Django, AIOHTTP, Sanic, ASGI) + payment helpers + 402 builders + discovery + Stripe multichain. The full merchant-side toolkit for AgentScore-powered agent commerce."
readme = "README.md"
license = "MIT"
Expand Down
12 changes: 12 additions & 0 deletions tests/test_checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,3 +985,15 @@ def test_rails_key_for_mppx_method_returns_none_when_rail_absent() -> None:
assert checkout._rails_key_for_mppx_method("solana") is None
assert checkout._rails_key_for_mppx_method("stripe") is None
assert checkout._rails_key_for_mppx_method("tempo") == "tempo"


def test_realm_from_url_derives_bare_host():
from agentscore_commerce.checkout import _realm_from_url

# Full endpoint URL -> bare host (matches the Node SDK's new URL(APP_URL).host),
# so the WWW-Authenticate realm is the protection space, not the full path.
assert _realm_from_url("https://agents.agentscore.com/purchase") == "agents.agentscore.com"
assert _realm_from_url("https://agents.example.com:8443/x/y") == "agents.example.com:8443"
# No parseable host: pass through unchanged.
assert _realm_from_url("agents.example.com") == "agents.example.com"
assert _realm_from_url("/purchase") == "/purchase"
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.