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-bridge

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
5.3 KB
---
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)

Overview

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.

How this skill works

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.

When to use it

  • Check upcoming events from one or all Google calendars programmatically.
  • List available calendars and fetch calendar metadata for automation or reporting.
  • Set up or troubleshoot Google Calendar OAuth for headless servers or bots.
  • Force a token refresh or confirm auth state via the health endpoint.
  • Run local automation that must avoid repeated interactive re-authentication.

Best practices

  • Run the bridge on the same host as your automation to avoid needing an API key for local calls.
  • Store GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in the bridge .env and keep tokens.json out of version control.
  • Use /health to verify authenticated state before making event queries.
  • Tunnel port 3000 when authorizing a remote server (ssh -L 3000:localhost:3000) and complete the browser consent once.
  • Configure systemd or another process supervisor to keep the service running long-term.

Example use cases

  • Quickly check the next 7 days of events: GET /events?days=7 from your automation script.
  • Aggregate events from all calendars for a daily agenda: GET /events?calendar=all&days=1.
  • List calendars to build a UI that allows users to select which calendar to query: GET /calendars.
  • Recover from revoked tokens by invoking the auth flow and completing consent via the returned /auth/url.
  • Run monitoring that calls /health to report authentication and service status to an ops dashboard.

FAQ

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.