Calendar Bridge Skill
Use this skill to interact with the Calendar Bridge service — a local REST API that wraps Google Calendar OAuth with persistent token storage and auto-refresh.
GitHub: https://github.com/DanielKillenberger/gcal-oauth-bridge
What is Calendar Bridge?
A tiny Node.js/Express service running at http://localhost:3000 that:
- Handles Google Calendar OAuth once via browser
- Stores and auto-refreshes tokens (solves the "token expired every 7 days" problem)
- Exposes a dead-simple REST API for events, calendars, and auth
API Endpoints
| Endpoint | Description |
|---|---|
GET /health | Service status + auth state |
GET /auth/url | Get OAuth consent URL |
GET /events?days=7 | Upcoming events from primary calendar |
GET /events?days=7&calendar=all | Events from ALL calendars |
GET /events?days=7&calendar=<id> | Events from a specific calendar |
GET /calendars | List all available calendars |
POST /auth/refresh | Force token refresh (normally automatic) |
Events response includes: id, summary, start, end, location, description, htmlLink, status, calendarId, calendarSummary
Checking Events
# Quick event check (7 days, primary calendar)
curl http://localhost:3000/events
# All calendars, next 14 days
curl http://localhost:3000/events?days=14&calendar=all
# With API key (if CALENDAR_BRIDGE_API_KEY is configured)
curl -H "Authorization: Bearer $API_KEY" http://localhost:3000/events?calendar=all
To call from OpenClaw/skill context (no API key needed when running on same host):
GET http://localhost:3000/events?calendar=all&days=7
First-Time Setup
1. Clone and install
git clone https://github.com/DanielKillenberger/gcal-oauth-bridge.git
cd gcal-oauth-bridge
npm install
cp .env.example .env
# Edit .env with GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET
2. Get Google OAuth credentials
- Go to https://console.cloud.google.com/apis/credentials
- Create OAuth 2.0 Client ID (Desktop app)
- Enable Google Calendar API
- Add redirect URI:
http://localhost:3000/auth/callback - Copy Client ID + Secret to
.env
3. Start the service
node app.js
# or: npm start
4. Authorize (one-time browser flow)
If on a remote VPS, first tunnel port 3000:
# From your local machine:
ssh -L 3000:localhost:3000 your-server
Then:
curl http://localhost:3000/auth/url
# Open the returned URL in your browser
# Complete Google consent → tokens saved automatically
Verify:
curl http://localhost:3000/health
# {"status":"ok","authenticated":true,"needsRefresh":false}
5. Keep it running (systemd)
systemctl --user enable calendar-bridge.service
systemctl --user start calendar-bridge.service
Re-authentication
If tokens are ever revoked (rare — auto-refresh prevents expiry):
ssh -L 3000:localhost:3000 your-servercurl http://localhost:3000/auth/url→ open URL → complete consent- Done — new tokens overwrite old ones
Troubleshooting
{"error":"Not authenticated"}→ Run the OAuth setup flow above401 Unauthorized→CALENDAR_BRIDGE_API_KEYis set; addAuthorization: Bearer <key>header- Can't reach localhost:3000 → Service not running; check
systemctl --user status calendar-bridge - "invalid_grant" / "token expired" → Tokens were revoked externally; re-authenticate
Personal Gmail Users
Works with personal Gmail. Google shows an "unverified app" warning — click Advanced → Go to [app] to proceed. Tokens are stored locally on your server, not shared with anyone.
Files
- GitHub repo: https://github.com/DanielKillenberger/gcal-oauth-bridge
- App:
app.js— main Express server - Config:
.env(from.env.example) - Tokens:
tokens.json(auto-generated, gitignored, never committed)