OAuth Token Health Tracking
Purpose: Monitor OAuth token expiration, refresh cycles, and prevent authentication failures.
Token Status Dashboard
| Service |
Status |
Last Refresh |
Expires |
Auto-Refresh |
Notes |
| Google Calendar |
✅ Healthy |
(check file mtime) |
N/A |
Yes |
/credentials/google-calendar-tokens.json |
| Google Drive |
✅ Healthy |
(check file mtime) |
N/A |
Yes |
/credentials/google-drive-tokens.json |
| UPS |
✅ Healthy |
(check file mtime) |
(check token) |
Yes |
/credentials/ups-token.json |
| Gmail |
🔴 Not setup |
- |
- |
- |
Not implemented |
| Zoho (all) |
🔴 Not setup |
- |
- |
- |
Not implemented |
Monitoring Protocol
Daily Health Check
Run this command to check token file freshness:
find /home/node/.openclaw/credentials -name "*token*.json" -mtime +7 -ls
Alert if: Any token file not modified in 7+ days (suggests stale or unused auth)
Weekly Review
Every Sunday (during rebuild window 9:45 PM PT):
- Check token file modification times
- Verify no expired tokens in logs
- Test one API call per service (smoke test)
- Document any refresh failures
Token Refresh Failure Response
If auto-refresh fails:
- Check credential file exists and is valid JSON
- Verify IP allowlist (if applicable, e.g. Vultr, UPS)
- Check API service status (provider outage?)
- Review error message for scope changes or revoked access
- If 3+ consecutive failures: Alert to Infrastructure & Tech group
- Manual re-auth if refresh token expired (rare, usually 6-12 month lifetime)
Google Services OAuth
Calendar & Drive
- Token Files:
- Access/Refresh:
/credentials/google-calendar-tokens.json
- Access/Refresh:
/credentials/google-drive-tokens.json
- Client Secrets:
/credentials/google-calendar-client-secret.json
/credentials/google-drive-client-secret.json
- Refresh Behavior: Automatic when access token expires (~1 hour lifetime)
- Refresh Token Lifetime: No expiration if used regularly
- Scopes:
- Calendar:
calendar.readonly
- Drive:
drive.readonly, drive.metadata.readonly
Gmail
- Status: ✅ Operational (auto-refresh implemented Feb 17, 2026)
- Required Scopes:
gmail.readonly, gmail.send
- Token Files:
- Access/Refresh:
/credentials/google-gmail-tokens.json (quan@ztag.com)
- Access/Refresh:
/credentials/google-gmail-gantom-tokens.json (quan@gantom.com)
- Access/Refresh:
/credentials/google-gmail-quan777-tokens.json (quan777@gmail.com)
- Client Secret:
/credentials/google-gmail-client-secret.json
- Refresh Behavior: Automatic via cron (every 45 minutes)
- Cron Job ID:
42f43a41-d500-4736-8951-178d3b478952
- Script:
/tools/gmail-refresh-all-tokens.py
- Access Token Lifetime: ~1 hour
- Refresh Token Lifetime: No expiration if used regularly
UPS OAuth
- Token File:
/credentials/ups-token.json
- API Config:
/credentials/ups-api.json
- Refresh Behavior: Automatic via
tools/ups-track.py
- Access Token Lifetime: ~1 hour
- Refresh Token Lifetime: Unknown (working since Feb 13, 2026)
- Account: 15BR09 (Quan's business account)
Zoho OAuth (Planned)
Multi-Service Complexity
Zoho uses single OAuth for all services (CRM, Books, Desk, Cliq, etc.)
- Status: Not implemented
- Token Files: (to be created)
- Access/Refresh:
/credentials/zoho-tokens.json
- Client Secret:
/credentials/zoho-client-secret.json
- Scopes Needed:
ZohoCRM.modules.ALL (read contacts, deals, accounts)
ZohoCRM.settings.ALL (read pipelines, stages)
ZohoBooks.fullaccess.all (read/write invoices, expenses)
Desk.tickets.READ (read support tickets)
Desk.tickets.UPDATE (update ticket status)
Cliq.Messages.CREATE (send team chat notifications)
- Refresh Behavior: Standard OAuth 2.0 (1-hour access tokens)
- Data Center: US (zoho.com, not zoho.eu or zoho.in)
- Implementation Priority: HIGH (blocks Tier 2 automation)
Zoho OAuth Setup Steps (When Ready)
- Create OAuth app in Zoho API Console
- Configure redirect URI (localhost for token exchange)
- Request required scopes
- Generate authorization code
- Exchange for access/refresh tokens
- Store in
/credentials/zoho-tokens.json
- Implement auto-refresh in automation scripts
- Test each service endpoint (CRM, Books, Desk, Cliq)
Token Security Best Practices
Storage
- ✅ All tokens in
/credentials/ (gitignored)
- ✅ JSON format with metadata
- ✅ File permissions: 600 (owner read/write only)
- ✅ Backed up to Quan's 1Password
Access Control
- ✅ Tokens never logged (even in debug mode)
- ✅ Tokens never transmitted (except to provider APIs via HTTPS)
- ✅ Tokens never committed to git
- ✅ Container volume mount (not baked into image)
Rotation
- Automatic: Access tokens via auto-refresh
- Manual Trigger: If refresh token compromised or revoked
- Provider Revocation: Re-auth required if app access revoked
- Emergency: Revoke all tokens, regenerate client secrets, re-auth
Alert Thresholds
Critical (Immediate Response)
- Any API returning 401 Unauthorized (expired/invalid token)
- Refresh token failure (can't get new access token)
- Service reporting "invalid grant" or "revoked access"
Warning (Review Within 24h)
- Token file not modified in 7+ days (may be unused)
- Multiple refresh attempts in short period (flapping)
- Unusual token usage patterns (possible compromise)
Info (Weekly Review)
- Token file modified (normal refresh activity)
- New token file created (new service integration)
- Scope change request from provider
Recovery Procedures
Lost or Corrupted Token File
- Check git history:
git log -- credentials/<service>-tokens.json
- Restore from 1Password backup
- If both fail: Re-authenticate from scratch
- Update token file path in all scripts
Provider Revoked Access
- Check provider console/email for revocation reason
- Review app permissions, scopes, terms of service
- Re-submit app for review if required
- Re-authenticate with corrected configuration
- Document incident in
incident-log.md
Scope Expansion Needed
- Update OAuth app configuration (provider console)
- Request additional scopes
- Re-authenticate to grant new permissions
- Update token file with new scope list
- Test new API endpoints
Last Updated: 2026-02-16
Next Review: Sunday 9:45 PM PT (weekly during rebuild window)