fix(google-workspace): normalize authorized user token writes

This commit is contained in:
LeonSGP43 2026-04-16 16:59:02 +08:00 committed by Teknium
parent f726b9b843
commit daef0519e9
5 changed files with 92 additions and 5 deletions

View file

@ -47,6 +47,13 @@ SCOPES = [
]
def _normalize_authorized_user_payload(payload: dict) -> dict:
normalized = dict(payload)
if not normalized.get("type"):
normalized["type"] = "authorized_user"
return normalized
def _ensure_authenticated():
if not TOKEN_PATH.exists():
print("Not authenticated. Run the setup script first:", file=sys.stderr)
@ -170,7 +177,12 @@ def get_credentials():
creds = Credentials.from_authorized_user_file(str(TOKEN_PATH), _stored_token_scopes())
if creds.expired and creds.refresh_token:
creds.refresh(Request())
TOKEN_PATH.write_text(creds.to_json())
TOKEN_PATH.write_text(
json.dumps(
_normalize_authorized_user_payload(json.loads(creds.to_json())),
indent=2,
)
)
if not creds.valid:
print("Token is invalid. Re-run setup.", file=sys.stderr)
sys.exit(1)

View file

@ -19,6 +19,13 @@ def get_token_path() -> Path:
return get_hermes_home() / "google_token.json"
def _normalize_authorized_user_payload(payload: dict) -> dict:
normalized = dict(payload)
if not normalized.get("type"):
normalized["type"] = "authorized_user"
return normalized
def refresh_token(token_data: dict) -> dict:
"""Refresh the access token using the refresh token."""
import urllib.error
@ -55,7 +62,9 @@ def refresh_token(token_data: dict) -> dict:
tz=timezone.utc,
).isoformat()
get_token_path().write_text(json.dumps(token_data, indent=2))
get_token_path().write_text(
json.dumps(_normalize_authorized_user_payload(token_data), indent=2)
)
return token_data

View file

@ -60,6 +60,13 @@ REQUIRED_PACKAGES = ["google-api-python-client", "google-auth-oauthlib", "google
REDIRECT_URI = "http://localhost:1"
def _normalize_authorized_user_payload(payload: dict) -> dict:
normalized = dict(payload)
if not normalized.get("type"):
normalized["type"] = "authorized_user"
return normalized
def _load_token_payload(path: Path = TOKEN_PATH) -> dict:
try:
return json.loads(path.read_text())
@ -151,7 +158,12 @@ def check_auth():
if creds.expired and creds.refresh_token:
try:
creds.refresh(Request())
TOKEN_PATH.write_text(creds.to_json())
TOKEN_PATH.write_text(
json.dumps(
_normalize_authorized_user_payload(json.loads(creds.to_json())),
indent=2,
)
)
missing_scopes = _missing_scopes_from_payload(_load_token_payload(TOKEN_PATH))
if missing_scopes:
print(f"AUTHENTICATED (partial): Token refreshed but missing {len(missing_scopes)} scopes:")
@ -313,7 +325,7 @@ def exchange_auth_code(code: str):
sys.exit(1)
creds = flow.credentials
token_payload = json.loads(creds.to_json())
token_payload = _normalize_authorized_user_payload(json.loads(creds.to_json()))
# Store only the scopes actually granted by the user, not what was requested.
# creds.to_json() writes the requested scopes, which causes refresh to fail