# Calendar Bridge

> Interact with the Calendar Bridge — a self-hosted Node.js service that provides a persistent REST API for Google Calendar events. Handles OAuth token auto-refresh so you never have to re-authenticate. Use when checking upcoming events, listing calendars, setting up Google Calendar access, or troubleshooting calendar auth.

- Skill: `johnalbertini14-glitch/calendar-bridge` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add johnalbertini14-glitch/calendar-bridge`
- Raw SKILL.md: https://api.skillmd.com/api/skills/johnalbertini14-glitch/calendar-bridge/raw
- Safety review: pending (external: skill-scanner WARNING, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: johnalbertini14-glitch (https://skillmd.com/u/johnalbertini14-glitch)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/johnalbertini14-glitch/calendar-bridge

---


# 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

```bash
# 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
```bash
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
```bash
node app.js
# or: npm start
```

### 4. Authorize (one-time browser flow)
If on a remote VPS, first tunnel port 3000:
```bash
# From your local machine:
ssh -L 3000:localhost:3000 your-server
```

Then:
```bash
curl http://localhost:3000/auth/url
# Open the returned URL in your browser
# Complete Google consent → tokens saved automatically
```

Verify:
```bash
curl http://localhost:3000/health
# {"status":"ok","authenticated":true,"needsRefresh":false}
```

### 5. Keep it running (systemd)
```bash
systemctl --user enable calendar-bridge.service
systemctl --user start calendar-bridge.service
```

## Re-authentication

If tokens are ever revoked (rare — auto-refresh prevents expiry):
1. `ssh -L 3000:localhost:3000 your-server`
2. `curl http://localhost:3000/auth/url` → open URL → complete consent
3. Done — new tokens overwrite old ones

## Troubleshooting

- **`{"error":"Not authenticated"}`** → Run the OAuth setup flow above
- **`401 Unauthorized`** → `CALENDAR_BRIDGE_API_KEY` is set; add `Authorization: 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)

