home / skills / openclaw / skills / gcal-oauth-bridge
This skill helps you check upcoming Google Calendar events and manage access via a self-hosted Calendar Bridge REST API with auto-refresh.
npx playbooks add skill openclaw/skills --skill gcal-oauth-bridgeReview the files below or copy the command above to add this skill to your agents.
---
name: calendar-bridge
description: 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.
homepage: https://github.com/DanielKillenberger/gcal-oauth-bridge
version: 1.0.2
read_when:
- User asks about upcoming events or calendar
- User asks what's scheduled or what meetings they have
- Calendar Bridge setup or troubleshooting needed
metadata:
{
"openclaw":
{
"emoji": "📅",
"requires": { "env": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"] },
"optional": { "env": ["CALENDAR_BRIDGE_API_KEY"] },
"notes": "GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET are required for initial OAuth setup only — once authenticated, the agent only needs network access to localhost:3000. CALENDAR_BRIDGE_API_KEY is optional; if set, the agent must send it as Authorization: Bearer <key> when calling /events. Tokens stored locally in tokens.json on your server, never sent externally."
}
}
triggers:
- what's on my calendar
- upcoming events
- check my calendar
- do I have anything scheduled
- what meetings do I have
- calendar today
- calendar this week
- calendar next week
- list my calendars
- google calendar
- calendar bridge
- set up calendar
- calendar auth
- calendar access
- calendar not working
---
# 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)
This skill provides a direct interface to the Calendar Bridge — a self-hosted Node.js service that wraps Google Calendar OAuth and exposes a persistent REST API for calendars and events. It handles one-time browser OAuth, persistent token storage, and automatic token refresh so you avoid repeated re-authentication. Use it to query upcoming events, list calendars, and manage calendar auth from local automation or bots.
The skill sends HTTP requests to the Calendar Bridge running (by default) at http://localhost:3000. It calls endpoints for health, auth, calendars, and events; the bridge handles OAuth consent once, stores tokens locally, and refreshes them automatically. When an API key is configured, requests can include an Authorization header; when running on the same host, no API key is required.
What if I see {"error":"Not authenticated"}?
Run the one-time OAuth browser flow: GET /auth/url, open the returned URL in a browser, complete Google consent. Tokens are saved automatically.
Why do I get 401 Unauthorized?
An API key is configured (CALENDAR_BRIDGE_API_KEY). Add Authorization: Bearer <key> to your request or call from the same host without the key.