Merge pull request #892 from jlowin/claude-wt-20250620-113451

This commit is contained in:
Jeremiah Lowin 2025-06-20 11:54:52 -04:00 committed by GitHub
commit a0242e1c68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 63 additions and 2 deletions

View file

@ -17,7 +17,7 @@ from mcp.shared.auth import (
OAuthClientInformationFull,
OAuthToken,
)
from pydantic import SecretStr
from pydantic import AnyHttpUrl, SecretStr, ValidationError
from fastmcp.server.auth.auth import (
ClientRegistrationOptions,
@ -179,8 +179,16 @@ class BearerAuthProvider(OAuthProvider):
if public_key and jwks_uri:
raise ValueError("Provide either public_key or jwks_uri, not both")
# Only pass issuer to parent if it's a valid URL, otherwise use default
# This allows the issuer claim validation to work with string issuers per RFC 7519
try:
issuer_url = AnyHttpUrl(issuer) if issuer else "https://fastmcp.example.com"
except ValidationError:
# Issuer is not a valid URL, use default for parent class
issuer_url = "https://fastmcp.example.com"
super().__init__(
issuer_url=issuer or "https://fastmcp.example.com",
issuer_url=issuer_url,
client_registration_options=ClientRegistrationOptions(enabled=False),
revocation_options=RevocationOptions(enabled=False),
required_scopes=required_scopes,

View file

@ -539,6 +539,59 @@ class TestBearerToken:
assert access_token is not None
assert access_token.client_id == "app456" # Should prefer client_id over sub
async def test_string_issuer_validation(self, rsa_key_pair: RSAKeyPair):
"""Test that string (non-URL) issuers are supported per RFC 7519."""
# Create provider with string issuer
provider = BearerAuthProvider(
public_key=rsa_key_pair.public_key,
issuer="my-service", # String issuer, not a URL
)
# Create token with matching string issuer
token = rsa_key_pair.create_token(
subject="test-user",
issuer="my-service", # Same string issuer
)
access_token = await provider.load_access_token(token)
assert access_token is not None
assert access_token.client_id == "test-user"
async def test_string_issuer_mismatch_rejection(self, rsa_key_pair: RSAKeyPair):
"""Test that mismatched string issuers are rejected."""
# Create provider with one string issuer
provider = BearerAuthProvider(
public_key=rsa_key_pair.public_key,
issuer="my-service",
)
# Create token with different string issuer
token = rsa_key_pair.create_token(
subject="test-user",
issuer="other-service", # Different string issuer
)
access_token = await provider.load_access_token(token)
assert access_token is None
async def test_url_issuer_still_works(self, rsa_key_pair: RSAKeyPair):
"""Test that URL issuers still work after the fix."""
# Create provider with URL issuer
provider = BearerAuthProvider(
public_key=rsa_key_pair.public_key,
issuer="https://my-auth-server.com", # URL issuer
)
# Create token with matching URL issuer
token = rsa_key_pair.create_token(
subject="test-user",
issuer="https://my-auth-server.com", # Same URL issuer
)
access_token = await provider.load_access_token(token)
assert access_token is not None
assert access_token.client_id == "test-user"
class TestFastMCPBearerAuth:
def test_bearer_auth(self):