GoogMeetSlack

Security

GoogMeetSlack sits between two identity providers (Slack and Google) and has real access to real calendars. We take that seriously. Here's exactly what happens.

Encryption at rest

OAuth refresh tokens for both Google and Slack are encrypted with AES-256-GCM before they touch our database. The 256-bit key is derived from a server-side secret via HKDF-SHA256 with a domain-separated context string, so future subkeys can never be confused with the encryption key.

Legacy rows written before the AES-256-GCM upgrade are Fernet (AES-128-CBC + HMAC-SHA256); they continue to decrypt on read and automatically rotate to the v2 envelope on their next write.

Slack webhook signature verification

Every inbound Slack webhook — slash commands, interactive payloads, event subscriptions — is verified by HMAC-SHA256 over the raw request body using Slack's signing secret, with a five-minute replay window and constant-time comparison.

Unsigned or stale requests are rejected with 401 before any handler runs. An unset signing secret is treated as an error, not as "allow everything."

OAuth minimum scopes

Google scopes we request:

  • calendar.events — create/delete only events this app made. Cannot read your calendar.
  • meetings.space.readonly — read transcripts of meetings you already can access.
  • openid email profile — your name + email for the account you connected.

Slack user scope is users.profile:write only. It cannot read messages or files.

Signed identity cookies

The cookie we set on your browser after you connect your Google account carries ids only — no credentials. It's signed with itsdangerous, HTTP-only, SameSite=Lax, Secure in production, and only honoured for the workspace it was issued in.

If the cookie is missing, tampered, or from another workspace, the Join link still works — it just doesn't route through your Google account. The redirect can never fail because of an optional feature.

Transcript handling

Transcripts are stored in the meeting organizer's own Google Drive by Google Meet. When you click Post transcript, our server briefly fetches the entries via the Google Meet API using your OAuth token, sends them to Gemini for summarization, and posts the result into the Slack thread.

We persist the AI summary metadata (used for the retention window and to render the dashboard) but we do not persist the raw transcript beyond that request.

Audit log

Every privileged action — meeting created, meeting cancelled, transcript posted, account connected/disconnected, settings changed — is written to an append-only audit log with the workspace, actor, action, and JSON detail. On the Business tier this log is exportable as CSV.

Infrastructure

Hosted on Render. Postgres with point-in-time recovery. Zero-downtime deploys. TLS via Render's Let's Encrypt integration. Region: us-east (Ohio). The service runs as an unprivileged worker with no filesystem writes outside a scratch directory; secrets come from the Render env, not from disk.

Reporting a vulnerability

Email security@gmslack.com with a description and proof of concept. Please do not open a public GitHub issue. We'll acknowledge within one business day and credit you in the security page if you'd like.