From 548a1903216075756ae7e6e6eecb671a78f38dd8 Mon Sep 17 00:00:00 2001 From: primorLee Date: Fri, 23 Oct 2026 01:10:00 +0800 Subject: [PATCH] fix(python): refresh zero-lifetime OAuth tokens (#3971) ## Summary - treat an OAuth `expires_in` value of zero as an explicit immediate expiration - refresh zero-lifetime tokens instead of caching them indefinitely - add a regression test covering two consecutive header requests ## Tests - `pytest python/tests/test_header_provider.py -q` (16 passed) - `ruff format --check python/lancedb/remote/header.py python/tests/test_header_provider.py` - `ruff check python/lancedb/remote/header.py python/tests/test_header_provider.py` --- python/python/lancedb/remote/header.py | 2 +- python/python/tests/test_header_provider.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/python/python/lancedb/remote/header.py b/python/python/lancedb/remote/header.py index 206b7a7cb..5f5bd12d8 100644 --- a/python/python/lancedb/remote/header.py +++ b/python/python/lancedb/remote/header.py @@ -141,7 +141,7 @@ class OAuthProvider(HeaderProvider): # Set expiration if provided expires_in = token_data.get("expires_in") - if expires_in: + if expires_in is not None: self._token_expires_at = time.time() + expires_in else: # Token doesn't expire or expiration unknown diff --git a/python/python/tests/test_header_provider.py b/python/python/tests/test_header_provider.py index 187b0a50a..e50ff3270 100644 --- a/python/python/tests/test_header_provider.py +++ b/python/python/tests/test_header_provider.py @@ -114,6 +114,24 @@ class TestOAuthProvider: "x-lancedb-credential-type": "oidc", } + def test_zero_lifetime_token_is_refreshed(self): + """A token that expires immediately must not be cached indefinitely.""" + call_count = 0 + + def fetcher(): + nonlocal call_count + call_count += 1 + return { + "access_token": f"token{call_count}", + "expires_in": 0, + } + + provider = OAuthProvider(fetcher, refresh_buffer_seconds=0) + + assert provider.get_headers() == {"Authorization": "Bearer token1"} + assert provider.get_headers() == {"Authorization": "Bearer token2"} + assert call_count == 2 + def test_missing_access_token(self): """Test error handling when access_token is missing."""