fix: load .env in doctor command; handle JWE tokens gracefully

Doctor was reading env vars before loading .env, so tokens set in .env
were invisible. ChatGPT now uses JWE (encrypted JWT) tokens which
PyJWT cannot decode without the server key — treat decode failure as
"token set, expiry unknown" rather than a FAIL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
JesseMarkowitz
2026-02-27 23:34:54 -05:00
parent 8e9ca36b57
commit b41634d892
2 changed files with 14 additions and 4 deletions

View File

@@ -125,8 +125,12 @@ def _validate_chatgpt_token(token: str) -> datetime | None:
try: try:
payload = jwt.decode(token, options={"verify_signature": False}) payload = jwt.decode(token, options={"verify_signature": False})
except jwt.DecodeError as e: except jwt.DecodeError:
logger.warning("CHATGPT_SESSION_TOKEN could not be decoded as JWT: %s", e) # JWE (encrypted JWT, alg=dir) — cannot be decoded without the server key.
# This is normal for ChatGPT's current token format. Token is valid; expiry unknown.
logger.debug(
"CHATGPT_SESSION_TOKEN is an encrypted JWE token — expiry cannot be decoded client-side."
)
return None return None
exp = payload.get("exp") exp = payload.get("exp")

View File

@@ -256,6 +256,10 @@ def _run_doctor_checks() -> list[dict]:
import os import os
import jwt as pyjwt import jwt as pyjwt
from datetime import timezone from datetime import timezone
from dotenv import load_dotenv
# Load .env so doctor works without the user having to export vars manually
load_dotenv(override=False)
checks = [] checks = []
@@ -288,8 +292,10 @@ def _run_doctor_checks() -> list[dict]:
add("ChatGPT token expiry warning", False, "Expires in < 24h — refresh soon") add("ChatGPT token expiry warning", False, "Expires in < 24h — refresh soon")
else: else:
add("ChatGPT token expiry", False, "JWT has no 'exp' claim") add("ChatGPT token expiry", False, "JWT has no 'exp' claim")
except Exception as e: except pyjwt.exceptions.DecodeError:
add("ChatGPT token decode", False, str(e)) # JWE (encrypted JWT) — cannot decode without the server key.
# This is normal for ChatGPT's current token format. Token is present and valid.
add("ChatGPT token expiry", True, "Encrypted token (JWE) — expiry not decodable client-side")
# Claude key # Claude key
if claude_key: if claude_key: