Purge standalone OAuth setup for Gmail and Gcal

- Deleted gmail_oauth_setup.py and gcal_oauth_setup.py (Skald handles OAuth)
- Removed google-auth-oauthlib dependency from requirements.txt and connector.json
- Simplified setup_instructions to point to Skald's OAuth flow
- Updated docstrings and error messages in *_mcp_server.py (no more refs to
  *_oauth_setup.py, point to Skald OAuth / env-var instead)
- connectors.json: removed oauth_setup.py from files[], updated sha256 hashes
This commit is contained in:
2026-07-17 21:53:17 +01:00
parent 46c1446eae
commit b1a3944fc8
9 changed files with 24 additions and 256 deletions
+2 -4
View File
@@ -11,12 +11,10 @@
],
"dependencies": [
"google-api-python-client>=2.150.0",
"google-auth>=2.35.0",
"google-auth-oauthlib>=1.2.0"
"google-auth>=2.35.0"
],
"setup_instructions": [
"Install dependencies: pip install -r requirements.txt",
"Run: python3 gmail_oauth_setup.py (optional, for standalone use — Skald handles OAuth)"
"Activated from Skald: an admin configures the Google sign-in provider, then each user signs in from the connector page (OAuth handled by Skald)."
],
"docs": [
{
+5 -8
View File
@@ -17,7 +17,6 @@ Provides read, modify, and send access to Gmail via the Gmail API v1.
Skald mode: Skald injects credentials via GMAIL_CREDS_JSON env var (authorized_user JSON).
Standalone mode: reads from GMAIL_CREDS_PATH or ./secrets/gmail_creds.json.
Run scripts/gmail_oauth_setup.py first to generate the OAuth token (standalone).
"""
from __future__ import annotations
@@ -308,21 +307,20 @@ def _format_google_error(e: Exception, api_label: str) -> str:
if RefreshError is not None and isinstance(e, RefreshError):
return (
f"Error: {api_label} API token refresh failed (the refresh token may have been revoked "
"or expired). Re-run scripts/gmail_oauth_setup.py to re-authenticate."
"or expired). Re-authenticate via Skald's OAuth flow (Sign in from the connector page)."
)
if HttpError is not None and isinstance(e, HttpError):
status = getattr(e, "status_code", None)
if status == 401:
return (
f"Error: {api_label} API rejected the access token (401). The OAuth token is invalid "
"or revoked. Re-run scripts/gmail_oauth_setup.py to re-authenticate."
)
f"Error: {api_label} API rejected the access token (401). The OAuth token is invalid "
"or revoked. Re-authenticate via Skald's OAuth flow (Sign in from the connector page)." )
if status == 403:
return (
f"Error: {api_label} API returned 403 Forbidden. The OAuth scopes granted are "
"insufficient for this operation, or the Gmail API is disabled in the Google Cloud "
"Console. Verify the scopes in scripts/gmail_oauth_setup.py and the API enablement."
"Console. Verify the scopes in the Google OAuth provider config and the API enablement."
)
if status == 404:
return (
@@ -482,9 +480,8 @@ def _gmail_status(args: dict | None = None) -> str:
except Exception as e:
return _status_report("", "AUTH_OR_API_ERROR", "action needed",
f"The Gmail API did not respond to the probe call: {_format_google_error(e, 'Gmail')}",
["Run scripts/gmail_oauth_setup.py to refresh / re-issue credentials.",
["Re-authenticate via Skald's OAuth flow (Sign in from the connector page).",
"If credentials are valid, verify the Gmail API is enabled in the Google Cloud Console."])
email = profile.get("emailAddress", "?")
return _status_report("", "READY", "ok",
"Google Gmail integration is operational: credentials load, the access token refreshes "
-108
View File
@@ -1,108 +0,0 @@
#!/usr/bin/env python3
"""Generate a Google OAuth token for Gmail API.
This script runs a local OAuth flow that:
1. Opens your browser automatically to the Google authorization page
2. Handles the callback via a local HTTP server
3. Saves the resulting token to ./secrets/gmail_creds.json
No manual copy-paste required.
"""
from __future__ import annotations
import json
import os
import sys
SCOPES = [
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/gmail.labels",
]
_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_PATH = os.path.join(_ROOT, "secrets", "gmail_creds.json")
_OAUTH_CLIENT_PATH = os.path.join(_ROOT, "secrets", "google_oauth_client.json")
def _load_oauth_client() -> tuple[str, str]:
if not os.path.exists(_OAUTH_CLIENT_PATH):
print(f"Missing OAuth client file: {_OAUTH_CLIENT_PATH}")
print("Create it with: {\"client_id\": \"...\", \"client_secret\": \"...\"}")
sys.exit(1)
with open(_OAUTH_CLIENT_PATH) as f:
data = json.load(f)
return data["client_id"], data["client_secret"]
def main() -> None:
# Lazy-import so we can show helpful errors if not installed.
try:
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
except ImportError as e:
print(f"Missing dependencies: {e}")
print("Install with: pip3 install google-auth google-auth-oauthlib google-api-python-client")
sys.exit(1)
creds = None
# Try to load existing credentials first, in case they have refresh token.
if os.path.exists(SECRET_PATH):
print(f"Existing credentials found at {SECRET_PATH}")
try:
creds = Credentials.from_authorized_user_file(SECRET_PATH, SCOPES)
except Exception:
creds = None
# If creds exist and are valid, we're good.
if creds and creds.valid:
print("Credentials are already valid!")
return
# If creds exist but expired, try to refresh.
if creds and creds.expired and creds.refresh_token:
print("Token expired. Attempting refresh...")
try:
creds.refresh(Request())
print("Token refreshed successfully!")
except Exception as e:
print(f"Refresh failed: {e}")
creds = None
if not creds or not creds.valid:
client_id, client_secret = _load_oauth_client()
# Start OAuth flow using local server (opens browser automatically).
flow = InstalledAppFlow.from_client_config(
{
"installed": {
"client_id": client_id,
"client_secret": client_secret,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"redirect_uris": ["http://localhost"],
}
},
SCOPES,
)
print("\nOpening browser for Google authorization...")
creds = flow.run_local_server(
port=0, # pick a random available port
open_browser=True,
prompt="consent",
access_type="offline",
)
# Save credentials.
os.makedirs(os.path.dirname(SECRET_PATH), exist_ok=True)
with open(SECRET_PATH, "w") as f:
f.write(creds.to_json())
print(f"\n✅ Gmail OAuth token saved to {SECRET_PATH}")
print(f" Scopes: {creds.scopes}")
if __name__ == "__main__":
main()
-1
View File
@@ -1,3 +1,2 @@
google-api-python-client>=2.150.0
google-auth>=2.35.0
google-auth-oauthlib>=1.2.0