Google auth

The one Google OAuth client and grant that Calendar, Gmail, and Drive share: creating it, authorizing it, where the tokens live, and what to do when the grant dies.

What it is

This guide walks through setting up Google OAuth2 credentials for Bee Box. These credentials are shared across all Google connectors (Calendar, Gmail API, Drive).

Create a Google Cloud project

  1. Go to console.cloud.google.com
  2. Click the project dropdown at the top → New Project
  3. Name it something like "Bee Box"
  4. Click Create

Enable APIs

In your new project, go to APIs & Services → Library and enable:

Search for each one and click Enable.

Configure the OAuth consent screen

Go to APIs & Services → OAuth consent screen:

  1. User type: External (even for personal use)
  2. App name: "Bee Box" (only you see this)
  3. User support email: your email
  4. Developer contact: your email
  5. Click through the rest — no need to add scopes here (they're requested at auth time)
  6. Under Test users, add your Google email address
  7. Leave the app in Testing mode — no need to publish for personal use

Note: In Testing mode, tokens expire every 7 days and you'll need to re-auth. If this becomes annoying, you can publish the app (it won't be listed anywhere since there's no homepage/verification).

Create OAuth credentials

Go to APIs & Services → Credentials:

  1. Click Create Credentials → OAuth 2.0 Client ID
  2. Application type: Web application (not Desktop)
  3. Name: "Bee Box" (or anything)
  4. Under Authorized redirect URIs, add the URIs for your setup:
    • Web (recommended): https://<your-server>/auth/google-services/callback
    • CLI: http://localhost:8976/oauth/callback
  5. Click Create
  6. Copy the Client ID and Client Secret. They serve two different surfaces, configured two different ways:
    • App login (signing in to beebox itself, before any box exists) reads them from the GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET env vars on the server — set those there.
    • A box's Google connectors (Calendar, Gmail, Drive) resolve the same pair from the machine secret store instead: bbx secrets set google-oauth-client-id, bbx secrets set google-oauth-client-secret, then bbx secrets grant <box> google-oauth-client-id (and the -secret name) for each box that needs them. Env vars are not read for this path.

Where tokens live

BBX_GOOGLE_TOKENS_FILE names a token file shared by every box that sees it (e.g., /home/beebox/.google-tokens.json). On a unit host, where each box is its own user and the variable is not passed to boxes, each box keeps its own token at ~/.config/beebox/google-tokens.json in the box user's home. Otherwise tokens fall back to per-box _config/connectors/google.secret.json, inside the box tree; bbx health warns about that file.

Authorize Bee Box

Web admin (recommended)

  1. Go to any box's Admin page
  2. In the Google Services section, click Connect Google Account
  3. You'll be redirected to Google for authorization
  4. After approving, you'll be redirected back. With BBX_GOOGLE_TOKENS_FILE, every box that shares that file now has the token; on a unit host (the server), only the box you connected from has it, so connect each box that needs Google

Per-box service policy

After connecting, enable specific services per box in each box's Admin page (Calendar, Gmail, Drive toggles). Or edit _config/box.json directly:

{
  "googleServices": {
    "calendar": true,
    "gmail": false,
    "drive": false
  }
}

If googleServices is missing, no Google services are enabled for that box (safe default).

Verify

Each connector's page has its own verify step; the quickest end-to-end check is the calendar pull.

Scopes authorized

ScopeDescription
calendar.eventsRead and write calendar events
gmail.readonlyRead all email
gmail.composeCreate drafts and send email
drive.readonlyRead all Drive files
drive.fileRead/write files created by the app
spreadsheetsRead and write Google Sheets

Troubleshooting

redirect_uri_mismatch

The redirect URI in your OAuth client must exactly match the one you're using. For CLI: http://localhost:8976/oauth/callback. For web: https://<your-server>/auth/google-services/callback. Check for trailing slashes or https vs http.

Token expired / invalid_grant

Google grants die on their own. If your OAuth consent screen is in Testing mode, refresh tokens expire every 7 days; an unverified Production app can also have its grant revoked. This is a property of BYO Google credentials, not a defect in the box.

The box detects it and says so rather than failing quietly. When a token refresh comes back invalid_grant:

Reconnect from the admin page's Google Services section (Re-authorize). The new grant clears the condition automatically.

The state is stored with the credential, so on a server sharing one BBX_GOOGLE_TOKENS_FILE across boxes, reconnecting once fixes every box.

Design notes: implemented-plans/google-auth-reauth-health.md.