Google Calendar
Proxy for the Google Calendar v3 REST API. Dual auth by design — the typical production setup runs two managed resources at once:
calendar-userinidp_passthroughmode for human users who want an agent to read their schedule, find free slots, or update their own events.calendar-roomsingoogle_samode for a booking agent that schedules meetings into Workspace resource (room) calendars on everyone's behalf.
Overview
The policy layer recognises this split and lets the operator lock each mode down differently:
- User-mode managed resources typically carry
read_only_calendar_idsfor calendars the user is on but shouldn't let an agent edit (shared team, executive). - Room-mode managed resources typically run with
room_only_mode: true, which refuses any call whosecalendar_idisn't a Workspace resource calendar (*@resource.calendar.google.com).
Default policy
The connector ships policy/calendar.rego
(package pbac.connectors.identos.google_calendar). It enforces four
things:
1. IdP-routing subject obligation
Same shape as drive/gmail — non-Google session + idp_passthrough mode
triggers a require_authn_at obligation.
2. private_calendar_ids deny (read + write)
deny contains msg if {
input.resource.type == "urn:connector:identos:google-calendar"
input.resource.calendar_id
some private in data[...].private_calendar_ids
input.resource.calendar_id == private
...
}
A "nuclear" deny: the calendar is off-limits to this connector entirely, reads and writes both blocked. Use it when the service account has been shared a sensitive calendar (executive, HR, legal) for one-off reasons but you don't want it exposed to LLM-driven workflows.
3. read_only_calendar_ids deny (write only)
Listed calendars allow GET but deny POST/PATCH/PUT/DELETE.
Reads still work — useful for agents that should surface but not modify
certain shared calendars.
4. room_only_mode deny
deny contains msg if {
input.resource.type == "urn:connector:identos:google-calendar"
data[...].room_only_mode == true
input.resource.calendar_id
not endswith(input.resource.calendar_id, "@resource.calendar.google.com")
...
}
A booking-agent safety net. When enabled, every calendar_id must look like a Workspace resource calendar. If the agent (or, more importantly, a prompt-injected response it's acting on) tries to touch a human calendar, the request is denied. Makes the service account's broad Workspace grants safe to deploy.
Supplying operator data
curl -X PUT http://localhost:8080/admin/policy/data/pbac/operator/connectors/identos.google-calendar \
-H "X-Admin-API-Key: $PBAC_ADMIN_API_KEY" \
-d '{
"private_calendar_ids": ["ceo@example.com"],
"read_only_calendar_ids": ["team-alpha@example.com"],
"room_only_mode": true
}'
Scope model
| Scope | Used for | |
|---|---|---|
| PBAC scopes (internal) | calendar:read, calendar:events:write, calendar:admin | Route authorization |
| Upstream OAuth scopes | calendar.readonly, calendar.events | Google-side grants the user consents to (idp_passthrough mode); the service-account flow doesn't use these |
See Google Workspace: multi-connector setup for how calendar's scopes compose with drive and gmail on one Google IdP.
Manifest reference
- ID:
identos.google-calendar - Version:
1.0.0 - Resource type:
urn:connector:identos:google-calendar
Supported auth modes
| Type | Details |
|---|---|
idp_passthrough | requires IdP google |
google_sa | setup fields: sa_key_env, domain |
Setup fields
| ID | Label | Default | Secret? | Notes |
|---|---|---|---|---|
base_url | API base URL | https://www.googleapis.com | no | — |
upstream_auth.type | Authentication | idp_passthrough | no | idp_passthrough forwards each user's own Google OAuth token (recommended). google_sa uses a Workspace service account with domain-wide delegation — useful for shared / room calendars where no human caller is involved. |
sa_key_env | Service account key | — | yes | Pick a secret containing the service-account JSON. Required only for the google_sa auth mode. / shown when upstream_auth.type == 'google_sa' |
domain | Workspace domain | — | no | placeholder: example.com / Required only for the google_sa auth mode. / shown when upstream_auth.type == 'google_sa' |
Scopes
| Scope |
|---|
calendar:read |
calendar:events:write |
calendar:admin |
Routes
| Method | Pattern | Scope | Resource template |
|---|---|---|---|
GET | /calendar/v3/users/me/calendarList | calendar:read | — |
GET | /calendar/v3/calendars/{calendar_id} | calendar:read | calendar://{{calendar_id}} |
GET | /calendar/v3/calendars/{calendar_id}/events | calendar:read | calendar://{{calendar_id}} |
GET | /calendar/v3/calendars/{calendar_id}/events/{event_id} | calendar:read | calendar://{{calendar_id}}/event/{{event_id}} |
POST | /calendar/v3/calendars/{calendar_id}/events | calendar:events:write | calendar://{{calendar_id}} |
PATCH | /calendar/v3/calendars/{calendar_id}/events/{event_id} | calendar:events:write | calendar://{{calendar_id}}/event/{{event_id}} |
DELETE | /calendar/v3/calendars/{calendar_id}/events/{event_id} | calendar:events:write | calendar://{{calendar_id}}/event/{{event_id}} |
POST | /calendar/v3/calendars/{calendar_id}/events/quickAdd | calendar:events:write | calendar://{{calendar_id}} |
POST | /calendar/v3/freeBusy | calendar:read | — |
GET | /calendar/v3/calendars/{calendar_id}/acl | calendar:admin | calendar://{{calendar_id}} |
MCP tools
| Name | Scope | Description |
|---|---|---|
list_calendars | calendar:read | List every calendar the authenticated user has on their calendar list (primary + shared + subscribed). |
get_calendar | calendar:read | Get a calendar's metadata (summary, timezone, description). |
list_events | calendar:read | List events on a calendar. Supports time filters (timeMin/timeMax), single-event expansion, and free-text search. |
get_event | calendar:read | Get a single event by ID. |
create_event | calendar:events:write | Create a new event on a calendar. Provide either the Google Calendar event body (full schema) or the convenience fields summary/start/end/attendees. |
update_event | calendar:events:write | Update an event (partial). Only supplied fields are modified. |
delete_event | calendar:events:write | Delete an event. Recurring events: pass sendUpdates=all to notify attendees. |
quick_add_event | calendar:events:write | Create an event from natural-language text (e.g. "Lunch with Alice Thursday 1pm"). Uses Calendar's quickAdd parser. |
query_free_busy | calendar:read | Query free/busy information for a set of calendars over a time window. Returns only busy intervals — no event details. |
list_acl | calendar:admin | List the access-control rules on a calendar (who it's shared with and how). |
Operator data schema
Keys the operator can supply under data.pbac.operator.connectors["identos.google-calendar"].* — consumed by the connector's policy.
| Key | Type | Description |
|---|---|---|
private_calendar_ids | array | Calendar IDs that are off-limits to this connector — reads and writes both denied. Useful for executive or HR-sensitive calendars that Workspace has shared to the service account but the operator wants shielded. |
read_only_calendar_ids | array | Calendar IDs where writes (create/update/delete) are denied regardless of the caller's scope. Reads still work. |
room_only_mode | boolean | When true, only calendars whose ID ends with @resource.calendar.google.com (Google Workspace resource/room calendars) are addressable. Useful for booking agents that should never touch human calendars. |