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
2 changes: 1 addition & 1 deletion src/mcp/client/auth/extensions/identity_assertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ async def _auth_flow(self, request: httpx2.Request) -> AsyncGenerator[httpx2.Req
self._expiry = calculate_token_expiry(self._tokens.expires_in) if self._tokens else None
self._initialized = True

if self._tokens and (self._expiry is None or time.time() <= self._expiry):
if self._tokens and (self._expiry is None or time.time() < self._expiry):
request.headers["Authorization"] = f"Bearer {self._tokens.access_token}"
response = yield request

Expand Down
2 changes: 1 addition & 1 deletion src/mcp/client/auth/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def is_token_valid(self) -> bool:
return bool(
self.current_tokens
and self.current_tokens.access_token
and (not self.token_expiry_time or time.time() <= self.token_expiry_time)
and (not self.token_expiry_time or time.time() < self.token_expiry_time)
)

def can_refresh_token(self) -> bool:
Expand Down
20 changes: 20 additions & 0 deletions tests/client/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,26 @@ async def test_token_validity_checking(self, oauth_provider: OAuthClientProvider
assert not context.is_token_valid()
assert context.can_refresh_token() # Can still refresh

# Exactly at expiry boundary (current time equals expiry)
now = time.time()
context.token_expiry_time = now
with mock.patch("time.time", return_value=now):
assert not context.is_token_valid() # Token must not be accepted on or after expiry

# Token with expires_in=0 should be immediately invalid at issuance time
zero_expiry_token = OAuthToken(
access_token="zero_token",
token_type="Bearer",
expires_in=0,
)
context.current_tokens = zero_expiry_token
with mock.patch("time.time", return_value=now):
context.update_token_expiry(zero_expiry_token)
assert not context.is_token_valid()

context.current_tokens = valid_tokens
context.token_expiry_time = time.time() - 100

# Remove refresh token
context.current_tokens.refresh_token = None
assert not context.can_refresh_token()
Expand Down
Loading