fix: googlechat gog oauth token loading

This commit is contained in:
iHildy 2026-01-26 18:45:09 -06:00
parent abe242a3bb
commit 3c1114d0e8
3 changed files with 43 additions and 18 deletions

View File

@ -77,16 +77,17 @@ If you already use `gog` for Google Workspace, you can reuse its OAuth client +
- For headless systems, switch to file keyring + password (see `gog` docs). citeturn6view0
4) Verify `gog` is visible to the gateway user:
```bash
gog auth tokens --json
gog auth tokens list --json
```
If this fails, install `gog` on the gateway host and ensure the keyring is accessible.
For non-interactive services, set `GOG_KEYRING_PASSWORD` in the gateway environment so `gog` can unlock the keyring.
Clawdbot reads `gog` OAuth client files from:
- `~/.config/gogcli/credentials.json`
- `~/.config/gogcli/credentials-<client>.json`
- `~/.config/gogcli/credentials-<domain>.json` (or macOS equivalent) citeturn9view0
Clawdbot queries `gog auth tokens --json` to reuse the stored refresh token. If this fails, set `oauthRefreshToken` manually.
Clawdbot queries `gog auth tokens list --json` (and falls back to `gog auth tokens export --json`) to reuse the stored refresh token. If this fails, set `oauthRefreshToken` manually.
### Option B: Manual OAuth
1) Configure OAuth consent + create OAuth client credentials in your Google Cloud project (desktop app recommended). citeturn6view0

View File

@ -543,6 +543,16 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
const configured = entry.configured === true;
if (!enabled || !configured) return [];
const issues = [];
if (entry.oauthFromGog && entry.userCredentialSource === "none") {
issues.push({
channel: "googlechat",
accountId,
kind: "auth",
message:
"Google Chat OAuth is set to reuse gog, but no gog OAuth credentials were detected.",
fix: "Ensure gog is installed and the keyring is unlocked (set GOG_KEYRING_PASSWORD), or set oauthRefreshToken/oauthClientFile manually.",
});
}
if (!entry.audience) {
issues.push({
channel: "googlechat",
@ -584,6 +594,8 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
enabled: account.enabled,
configured: account.credentialSource !== "none",
credentialSource: account.credentialSource,
oauthFromGog: account.config.oauthFromGog ?? false,
userCredentialSource: account.userCredentialSource,
audienceType: account.config.audienceType,
audience: account.config.audience,
webhookPath: account.config.webhookPath,

View File

@ -109,25 +109,37 @@ export function readGogRefreshTokenSync(params: {
const cached = tokenCache.get(cacheKey);
if (cached) return cached;
let stdout = "";
try {
stdout = execFileSync("gog", ["auth", "tokens", "--json"], {
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
});
} catch {
return null;
}
const env = {
...process.env,
...(params.gogAccount?.trim() ? { GOG_ACCOUNT: params.gogAccount.trim() } : {}),
...(params.gogClient?.trim() ? { GOG_CLIENT: params.gogClient.trim() } : {}),
};
let parsed: unknown;
try {
parsed = JSON.parse(stdout);
} catch {
return null;
}
const runGogJson = (args: string[]): unknown | null => {
try {
const stdout = execFileSync("gog", ["--no-input", ...args], {
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
timeout: 3000,
env,
});
return JSON.parse(stdout);
} catch {
return null;
}
};
const parsed = runGogJson(["auth", "tokens", "list", "--json"]);
const tokens: GogTokenEntry[] = [];
collectTokens(parsed, tokens);
if (parsed) {
collectTokens(parsed, tokens);
}
if (tokens.length === 0) {
const exported = runGogJson(["auth", "tokens", "export", "--json"]);
if (exported) {
collectTokens(exported, tokens);
}
}
if (tokens.length === 0) return null;
const target = params.gogAccount?.trim().toLowerCase();