feat(kiloclaw): Google account access for bots#949
Open
Conversation
Add GoogleCredentials schema (encrypted clientSecret + credentials envelopes), DO storage/retrieval methods, googleConnected status field, and env builder decryption into GOOGLE_CLIENT_SECRET_JSON / GOOGLE_CREDENTIALS_JSON.
…s writer Add POST/DELETE /api/platform/google-credentials routes for storing and clearing encrypted Google credentials. Add gws-credentials module that writes client_secret.json and credentials.json to ~/.config/gws/ on controller startup when the env vars are present.
Docker container that orchestrates the Google OAuth flow: gws auth setup -> gws auth login -> encrypt credentials -> POST to platform. Published as kilocode/google-setup for users to run locally.
Contributor
Code Review SummaryStatus: 2 Issues Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
Other Observations (not in diff)N/A Files Reviewed (32 files)
Reviewed by gpt-5.4-20260305 · 624,195 tokens |
GET /api/platform/public-key derives the RSA public key from the worker's private key so the google-setup container can encrypt credentials before POSTing them.
- Move public-key endpoint to /public-key (public, no auth needed) - Add POST/DELETE /api/admin/google-credentials (JWT auth, auto-resolves userId) - Update setup.mjs to use Bearer auth against the worker directly instead of x-internal-api-key against the platform API
Add .dockerignore for google-setup. Mark gws CLI npm package as pending publication with a TODO and graceful build fallback.
Add types, internal client methods, and tRPC mutations for managing Google credentials from the dashboard (connectGoogle/disconnectGoogle).
- Use non-destructive auth probe in setup.mjs (GET /api/admin/storage instead of DELETE /api/admin/google-credentials) - Clean up stale gws credential files on disconnect (controller) - Add googleConnected to getDebugState() return type - Exclude googleCredentials from ProvisionRequestSchema
Install @googleworkspace/cli (https://github.com/googleworkspace/cli) instead of the non-existent @anthropic/gws placeholder. Remove the || echo fallback so the build fails fast if install fails.
Node.js script that tests public-key endpoint, platform API store/clear, JWT auth routes, input validation, and idempotency against a local worker. Creates a temporary DB user for JWT auth and cleans up after.
- Add gcloud CLI to Dockerfile (required by `gws auth setup`) - Replace gws auth login with our own Node.js OAuth flow to avoid gws's encrypted credential store (keyring issues in Docker) - Add google-setup-e2e.mjs: end-to-end test that provisions a user, builds the Docker image, runs the interactive OAuth flow, and verifies googleConnected=true
Show docker setup command with copy button when not connected, and a disconnect button when connected. Adds connectGoogle and disconnectGoogle mutations to useKiloClawMutations hook.
Add getGoogleSetupCommand tRPC query that generates the docker command with the user's API key pre-filled, so they can just copy and paste without visiting the Profile page.
Update Docker image reference to ghcr.io/kilo-org/google-setup and add README with multi-arch build and publishing instructions.
Install @googleworkspace/cli (gws) so bots can use Google Workspace APIs with the credentials written by the controller at startup.
…nnected Runs `npx skills add` in the background after writing Google credentials, so OpenClaw agents automatically get access to 90+ Google Workspace skills.
OpenClaw changes HOME to the workspace dir at runtime, so gws can't find credentials at ~/.config/gws/. Hardcode /root/.config/gws and set the env var so gws finds them regardless of HOME.
… code - Read secrets from .dev.vars instead of hardcoded defaults - Fix public-key endpoint path: /public-key → /api/admin/public-key - Public-key test now uses JWT auth (endpoint is behind auth)
…low provision - Read secrets from .dev.vars instead of hardcoded defaults - Use fire-and-forget provision with DO polling (handles Fly timeouts) - Use safer env-var-based sql() helper
The gog config tarball includes OAuth tokens, client secrets, and keyring data for 13+ services. 32 KiB of encrypted base64 could get tight as gog adds more data over time. 64 KiB gives more breathing room.
The same password string is hardcoded in 3 locations across different languages. Add comments cross-referencing all three so future changes don't miss one.
Each refetch generates a new 1-hour JWT. The 50-minute refetchInterval is sufficient; window focus refetches are unnecessary churn.
On reconnect (disconnect → new connect → redeploy), files from the old bundle that don't exist in the new one would linger. rmSync the config dir before unpacking to ensure a clean slate.
Defense-in-depth against path traversal in user-supplied tarballs. The tarball is encrypted with the worker's RSA key so exploitation requires compromising that key, but the flag is cheap insurance.
Previously only 401/403 were rejected, so a 500/503 would fall through as "verified" and send the user through the entire OAuth flow before failing at the final POST step.
make startController wait for credentials write, exposing gog env vars to the child process on first spawn; preserve best-effort error handling by logging and continuing startup
Run `gog auth list --json` after OAuth flow to confirm the account was actually stored before creating and uploading the config tarball.
This flag was causing tar extraction to fail silently on the container, resulting in empty gogcli config directories and no Google credentials.
…account-access # Conflicts: # src/app/(app)/claw/components/SettingsTab.tsx
Reconnecting requires re-running the full Docker OAuth setup flow, so accidental disconnects are costly. Use ConfirmActionDialog to match the pattern used by other destructive actions in SettingsTab.
St0rmz1
reviewed
Mar 12, 2026
Contributor
St0rmz1
left a comment
There was a problem hiding this comment.
Is GOG_KEYRING_PASSWORD intended to remain hardcoded as a plaintext string in three production files (controller/src/gog-credentials.ts, start-openclaw.sh, google-setup/setup.mjs)? I understand it's needed to avoid TTY prompts from the 99designs/keyring file backend, but is there a reason this couldn't be pulled from an env var or a shared constant so it's not scattered across TypeScript, shell, and JS?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds end-to-end Google account access for kiloclaw bots: credential storage, a Docker-based OAuth setup flow, encrypted credential delivery to containers, and a Settings UI for managing connections.
Google Setup Docker image (
kiloclaw/google-setup/)setup.mjs) that walks the user through:gcloud auth login(browser-based)gog auth credentials set+gog auth add --services=allto authorize~/.config/gogcli/, encrypt with RSA-AES-256-GCM envelope, POST to workerghcr.io/kilo-org/google-setup, multi-arch amd64+arm64)Credential storage & API (kiloclaw worker)
GoogleCredentialsschema: encryptedgogConfigTarball(EncryptedEnvelope, max 32 KiB) + optional displayemailGET /api/admin/public-key— derives and caches RSA public key from stored private keyPOST/GET/DELETE /api/admin/google-credentials— store, check status, clear credentialsPOST/DELETE /api/platform/google-credentials— platform-level store/clear endpointsgoogleConnectedboolean exposed in instance status responsebuildEnvVars)Controller credential writer (
gog-credentials)gog-credentials.tsmodule extracts a pre-built gog config tarball to~/.config/gogcli/on container startupGOG_KEYRING_BACKEND=file,GOG_KEYRING_PASSWORD=kiloclaw,GOG_ACCOUNT=<email>env varsContainer image & startup
gogCLI (gogcli v0.11.0) already installed via Go in Dockerfileuv(Python package manager) installed to/usr/local/binstart-openclaw.shadditions:KILOCLAW_ENC_*→ plaintext via AES-256-GCM)npm-global-prefix,pip-global-prefix,uv-global-prefix(redirect installs to persistent volume)GOG_KEYRING_PASSWORDexported for gog CLIGOOGLE_GOG_CONFIG_TARBALLclassified as internal sensitive env var in secret-catalogNext.js frontend
GoogleAccountSectionin Settings tab: connection badge, docker setup command with copy button, disconnect button--worker-urlflag for local testinggetGoogleSetupCommand,disconnectGoogleTest plan
gog --versionworks, tarball extraction verified