Skip to content

Commit 33822d0

Browse files
committed
fix(auth): align max token age with reauth warning
1 parent bd9d7f5 commit 33822d0

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

src/schwab_mcp/auth.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
from schwab_mcp import tokens
1414

15+
16+
DEFAULT_MAX_TOKEN_AGE_SECONDS = 5 * 24 * 60 * 60
17+
1518
if TYPE_CHECKING:
1619
from multiprocessing import Process as ProcessType, Queue as QueueType
1720
else: # pragma: no cover - runtime fallback for multiprocess
@@ -29,7 +32,7 @@ def easy_client(
2932
token_manager: tokens.Manager,
3033
asyncio: bool = False,
3134
enforce_enums: bool = True,
32-
max_token_age: int | None = 60 * 60 * 24 * 13 // 2,
35+
max_token_age: int | None = DEFAULT_MAX_TOKEN_AGE_SECONDS,
3336
callback_timeout: float = 300.0,
3437
interactive: bool = True,
3538
requested_browser: str | None = None,

src/schwab_mcp/cli.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616

1717
APP_NAME = "schwab-mcp"
18+
TOKEN_MAX_AGE_SECONDS = schwab_auth.DEFAULT_MAX_TOKEN_AGE_SECONDS
1819

1920

2021
@click.group()
@@ -68,6 +69,7 @@ def auth(
6869
client_secret=client_secret,
6970
callback_url=callback_url,
7071
token_manager=token_manager,
72+
max_token_age=TOKEN_MAX_AGE_SECONDS,
7173
)
7274

7375
# If we get here, the authentication was successful
@@ -162,6 +164,7 @@ def server(
162164
asyncio=True,
163165
interactive=False,
164166
enforce_enums=False,
167+
max_token_age=TOKEN_MAX_AGE_SECONDS,
165168
)
166169

167170
if not isinstance(client, AsyncClient):
@@ -180,7 +183,7 @@ def server(
180183
return 1
181184

182185
# Check token age
183-
if client.token_age() > 5 * 86400:
186+
if client.token_age() >= TOKEN_MAX_AGE_SECONDS:
184187
send_error_response(
185188
"Token is older than 5 days. Please run 'schwab-mcp auth' to re-authenticate.",
186189
code=401,

tests/test_cli_auth.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from __future__ import annotations
2+
3+
from click.testing import CliRunner
4+
5+
from schwab_mcp import cli
6+
7+
8+
def test_auth_command_uses_max_token_age(monkeypatch, tmp_path):
9+
captured: dict[str, object] = {}
10+
11+
class DummyManager:
12+
def __init__(self, path: str) -> None:
13+
self.path = path
14+
captured["token_path"] = path
15+
16+
def fake_easy_client(**kwargs):
17+
captured["easy_client_kwargs"] = kwargs
18+
return object()
19+
20+
monkeypatch.setattr(cli.tokens, "Manager", DummyManager)
21+
monkeypatch.setattr(cli.schwab_auth, "easy_client", fake_easy_client)
22+
23+
runner = CliRunner()
24+
token_file = tmp_path / "token.yaml"
25+
result = runner.invoke(
26+
cli.cli,
27+
[
28+
"auth",
29+
"--token-path",
30+
str(token_file),
31+
"--client-id",
32+
"cid",
33+
"--client-secret",
34+
"secret",
35+
],
36+
catch_exceptions=False,
37+
)
38+
39+
assert result.exit_code == 0
40+
assert captured["token_path"] == str(token_file)
41+
assert captured["easy_client_kwargs"]["max_token_age"] == cli.TOKEN_MAX_AGE_SECONDS

tests/test_cli_server_write_modes.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def _patch_common(monkeypatch, captured):
3939

4040
def fake_easy_client(**_kwargs):
4141
captured["easy_client_called"] = True
42+
captured["easy_client_kwargs"] = _kwargs
4243
return FakeAsyncClient()
4344

4445
monkeypatch.setattr(cli.schwab_auth, "easy_client", fake_easy_client)
@@ -77,6 +78,7 @@ def test_server_defaults_to_read_only(monkeypatch):
7778
assert result.exit_code == 0
7879
assert captured["allow_write"] is False
7980
assert isinstance(captured["approval_manager"], NoOpApprovalManager)
81+
assert captured["easy_client_kwargs"]["max_token_age"] == cli.TOKEN_MAX_AGE_SECONDS
8082

8183

8284
def test_server_enables_write_mode_when_flag_set(monkeypatch):
@@ -100,6 +102,7 @@ def test_server_enables_write_mode_when_flag_set(monkeypatch):
100102
assert result.exit_code == 0
101103
assert captured["allow_write"] is True
102104
assert isinstance(captured["approval_manager"], NoOpApprovalManager)
105+
assert captured["easy_client_kwargs"]["max_token_age"] == cli.TOKEN_MAX_AGE_SECONDS
103106

104107

105108
def test_server_enables_write_mode_with_discord(monkeypatch):
@@ -129,3 +132,4 @@ def test_server_enables_write_mode_with_discord(monkeypatch):
129132
assert result.exit_code == 0
130133
assert captured["allow_write"] is True
131134
assert isinstance(captured["approval_manager"], DummyDiscordApprovalManager)
135+
assert captured["easy_client_kwargs"]["max_token_age"] == cli.TOKEN_MAX_AGE_SECONDS

0 commit comments

Comments
 (0)