Connect a Google Calendar
This guide shows you how to connect Google Calendar to a workspace. It’s per-workspace: it syncs that workspace’s events into Control Center, read-only. See Calendar and scheduling for the full picture.
Connect an account
Section titled “Connect an account”- Open Calendar in the sidebar.
- Click Add calendar account in the calendar sidebar. (The same section lives at Settings → You → Profile & identity, under Google Calendar.)
- Choose how to authorize:
- Use Control Center’s Google app — nothing to set up. This is the default when your build ships with one.
- Use my own Google Cloud client — paste a client id and secret from your own project (see Bring your own Google client).
- Click Connect Google Calendar. The dialog shows a short code and a link to Google’s device page.
- Open that page on any device, enter the code and approve the requested access. The dialog closes on its own and your events begin syncing.
The server, not your device, runs this exchange and keeps the resulting refresh token — which is why the code is approved on “any device” rather than in this app specifically.
The account is connected to the active workspace only. Switch workspaces and you’ll see that workspace’s calendars instead.
How syncing works
Section titled “How syncing works”The server owns the schedule: it sweeps every workspace’s connected accounts every two minutes and writes the events into the workspace’s database. Clients never talk to Google — they read what the server wrote.
The sweep is incremental. The first pass per calendar fetches a rolling window (60 days back, 90 days ahead) and captures Google’s sync token; later passes present that token and receive only what changed, which is what makes a two-minute cadence affordable. The window is re-anchored with a full sync every 24 hours and whenever Google invalidates the token.
Refresh tokens live server-side in secrets.json under the server’s data
directory, written owner-only (0600) — not in the OS keychain and never on a
client device.
Connect multiple accounts
Section titled “Connect multiple accounts”A workspace can connect several Google accounts (for example work and personal). Repeat the connect step for each; their events merge into the same month / week / agenda views. Each account syncs and refreshes independently and each can be disconnected on its own.
Reconnect an expired account
Section titled “Reconnect an expired account”If Google permanently invalidates an account’s token (a revoked or long-expired session), syncing stops and Control Center shows a Reconnect banner on the calendar, plus a desktop notification. Click Reconnect and approve a new code; the banner clears on the next successful sync.
Disconnect an account
Section titled “Disconnect an account”From the calendar sidebar (or Settings → You → Profile & identity), click Disconnect on the account. This deletes its synced events and clears its stored tokens on the server.
Connect from a headless server
Section titled “Connect from a headless server”A server with no GUI attached connects the same account from its own terminal:
cc_server calendar connect --data-dir <dir> --workspace <workspace-id> \ --google-client-id <id> --google-client-secret <secret>It prints a code and a URL, waits for approval, then stores the tokens and syncs on the next sweep.
A build from source ships no Google client, so the id and secret are
required — pass them as flags, or set GOOGLE_OAUTH_CLIENT_ID and
GOOGLE_OAUTH_CLIENT_SECRET. Without them the command exits with a
missing-client error.
Bring your own Google client (forks and self-hosting)
Section titled “Bring your own Google client (forks and self-hosting)”Released builds ship with a Google client, so most people never touch this. Bring your own if you build from source, run your own server, want the consent screen to name your own project, or need RSVP to work.
- In the Google Cloud Console, enable the Google Calendar API and configure the OAuth consent screen, adding the
calendar.readonly,openidandemailscopes. Addhttps://www.googleapis.com/auth/calendar.eventsas well if you want RSVP writes to succeed. While the app is unverified, add yourself as a test user. - Create an OAuth client ID of application type TVs and limited input devices and copy both the client id and the client secret.
- Supply them either per-connect (choose Use my own Google Cloud client in the dialog) or server-wide with
GOOGLE_OAUTH_CLIENT_IDandGOOGLE_OAUTH_CLIENT_SECRET(equivalently--google-client-id/--google-client-secret).
A server-wide pair replaces the built-in one everywhere, including behind the “use Control Center’s Google app” option — so on your own server, that option is your app.
The client secret never leaves the server: no RPC response carries it and an account connected through the server’s own client stores a marker rather than a copy of the pair, so rotating it is a matter of restarting with a new value.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause |
|---|---|
| The dialog offers no built-in option | This build ships no Google client (a source build), or the server was started with only one half of the pair. Both the id and the secret are required |
invalid_scope when starting the flow |
Calendar is not permitted for a device-code client in that Cloud project. Use a loopback or web client project instead |
invalid_client from Google |
The client is not a TVs and limited input devices client, or the id and secret are from different clients |
| Approval succeeds but sync is empty | Your account is not a test user on the consent screen, or calendar.readonly was not granted |
| The code expires before you approve it | Device codes are short-lived. Start the connect again for a fresh one |
| “Couldn’t update your response” on an RSVP | The account was connected without the calendar.events scope — expected for the built-in flow |
| Sync stops with a refresh warning in the server log | The account was connected with a client that is no longer configured. Reconnect the account, or restore that client id and secret |
Related guides
Section titled “Related guides”- Record and summarize a meeting: turn an event into a recording
- Run a headless server: where the tokens and the sync schedule live
- Set up GitHub integration