Skip to content

Commit ff6f995

Browse files
rustyconoverclaude
andcommitted
Exempt CORS preflight OPTIONS from auth middleware (v0.6.1)
Browsers do not send credentials on CORS preflight requests, so _AuthMiddleware must skip OPTIONS to let CORSMiddleware respond with the proper Access-Control-* headers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9ed43d8 commit ff6f995

3 files changed

Lines changed: 21 additions & 4 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "vgi-rpc"
3-
version = "0.6.0"
3+
version = "0.6.1"
44
description = "Vector Gateway Interface - RPC framework based on Apache Arrow"
55
readme = "README.md"
66
requires-python = ">=3.13"

tests/test_http.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,21 @@ def test_no_auth_middleware_when_authenticate_is_none(self) -> None:
10741074
assert result == "anonymous"
10751075
client.close()
10761076

1077+
def test_cors_preflight_bypasses_auth(self) -> None:
1078+
"""OPTIONS preflight must not be rejected by auth middleware."""
1079+
server = RpcServer(_AuthService, _AuthServiceImpl())
1080+
app = make_wsgi_app(
1081+
server,
1082+
signing_key=b"test",
1083+
cors_origins="*",
1084+
authenticate=_test_authenticate,
1085+
)
1086+
tc = falcon.testing.TestClient(app)
1087+
# Simulate a CORS preflight — no Authorization header
1088+
resp = tc.simulate_options("/whoami", headers={"Origin": "http://example.com"})
1089+
assert resp.status != "401 Unauthorized"
1090+
assert resp.headers.get("access-control-allow-origin") == "*"
1091+
10771092

10781093
# ---------------------------------------------------------------------------
10791094
# Tests: CORS

vgi_rpc/http/_server.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,10 +1822,12 @@ def process_request(self, req: falcon.Request, resp: falcon.Response) -> None:
18221822
The 401 response is plain text (not Arrow IPC) because at this
18231823
stage no method has been resolved and the output schema is unknown.
18241824
1825-
Well-known paths (``/.well-known/``) are exempt from authentication
1826-
so that clients can discover OAuth metadata before authenticating.
1825+
CORS preflight ``OPTIONS`` requests and well-known paths
1826+
(``/.well-known/``) are exempt from authentication so that browsers
1827+
can complete the preflight handshake without credentials and clients
1828+
can discover OAuth metadata before authenticating.
18271829
"""
1828-
if req.path.startswith("/.well-known/"):
1830+
if req.method == "OPTIONS" or req.path.startswith("/.well-known/"):
18291831
return
18301832
try:
18311833
auth = self._authenticate(req)

0 commit comments

Comments
 (0)