different-ai/openwork · error · Error
Missing Google OAuth configuration: ${missing.join(", ")}
Error message
Missing Google OAuth configuration: ${missing.join(", ")} What it means
The Google Workspace extension throws this when resolving OAuth credentials via googleWorkspaceCredentials() before exchanging an authorization code for tokens. The helper reads GOOGLE_WORKSPACE_CLIENT_ID / GOOGLE_WORKSPACE_CLIENT_SECRET (with legacy fallbacks) from the environment; if the client secret is absent and no token broker URL is configured, the missing list is non-empty and the exchange is refused. The bundled desktop client ID is used by default, so this is almost always a missing/empty secret or a secret env var typo when running a custom client.
Source
Thrown at apps/server/src/extensions/google-workspace.ts:569
? payload.error
: response.statusText
: response.statusText;
throw new Error(`Google request failed (${response.status}): ${details}`);
}
return payload;
}
async function fetchGoogleUserInfo(accessToken: string) {
return fetchGoogleJson("https://www.googleapis.com/oauth2/v3/userinfo", { headers: { Authorization: `Bearer ${accessToken}` } });
}
async function fetchGoogleWorkspaceTokenBrokerJson(tokenBrokerUrl: string, body: Record<string, unknown>) {
return fetchGoogleJson(tokenBrokerUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
}
async function exchangeGoogleWorkspaceCode(input: { code: string; redirectUri: string; verifier: string }) {
const { clientId, clientSecret, tokenBrokerUrl, missing } = googleWorkspaceCredentials();
if (missing.length > 0) throw new Error(`Missing Google OAuth configuration: ${missing.join(", ")}`);
if (tokenBrokerUrl) {
return fetchGoogleWorkspaceTokenBrokerJson(tokenBrokerUrl, {
grantType: "authorization_code",
provider: GOOGLE_WORKSPACE_EXTENSION_ID,
clientId,
code: input.code,
codeVerifier: input.verifier,
redirectUri: input.redirectUri,
});
}
return fetchGoogleJson("https://oauth2.googleapis.com/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
code: input.code,
code_verifier: input.verifier,View on GitHub (pinned to 2b7df46e8a)
Solutions
- Set the GOOGLE_WORKSPACE_CLIENT_SECRET environment variable (or the legacy variant it falls back to) to your OAuth client secret and restart the server
- Alternatively set GOOGLE_WORKSPACE_TOKEN_BROKER_URL so tokens are exchanged via the token broker and no secret is needed locally
- Check the exact env var names against googleWorkspaceCredentials() in apps/server/src/extensions/google-workspace.ts:321 — whitespace-only values are treated as missing
- Call the connect status endpoint (googleWorkspaceStatusPayload reports `configured`/`missing`) before starting a connect flow
Example fix
// before GOOGLE_WORKSPACE_CLIENT_ID=my-client.apps.googleusercontent.com google oauth connect ... // Error: Missing Google OAuth configuration: GOOGLE_WORKSPACE_CLIENT_SECRET // after GOOGLE_WORKSPACE_CLIENT_ID=my-client.apps.googleusercontent.com GOOGLE_WORKSPACE_CLIENT_SECRET=GOCSPX-xxxx google oauth connect ... // succeeds
Defensive patterns
Strategy: validation
Validate before calling
const credentials = googleWorkspaceCredentials();
if (credentials.missing.length > 0) {
throw new Error(`Configure before connecting Google Workspace: missing ${credentials.missing.join(", ")}`);
}
// or without internals:
if (!process.env.GOOGLE_WORKSPACE_CLIENT_SECRET && !process.env.GOOGLE_WORKSPACE_TOKEN_BROKER_URL) {
throw new Error("Set GOOGLE_WORKSPACE_CLIENT_SECRET or GOOGLE_WORKSPACE_TOKEN_BROKER_URL first");
} Type guard
function isGoogleOauthConfigured(): boolean {
return Boolean(
process.env.GOOGLE_WORKSPACE_CLIENT_SECRET?.trim() ||
process.env.GOOGLE_WORKSPACE_TOKEN_BROKER_URL?.trim(),
);
} Try / catch
try {
await startGoogleWorkspaceConnect();
} catch (err) {
if (err instanceof Error && err.message.startsWith("Missing Google OAuth configuration")) {
showSetupGuide(err.message.split(": ")[1]?.split(", ") ?? []);
return;
}
throw err;
} Prevention
- Always check the connect/status endpoint (reports configured + missing vars) before starting a connect flow
- Keep OAuth env vars in a versioned env template so deployments get all required names
- Remember empty/whitespace values count as missing — validate env files after edits
- When using a custom client ID, provision the secret in the same change
When it happens
Trigger: Calling the OAuth connect flow (exchangeGoogleWorkspaceCode with a valid code/redirectUri/verifier) when googleWorkspaceCredentials().missing is non-empty — i.e. neither GOOGLE_WORKSPACE_CLIENT_SECRET nor its legacy variant is set AND GOOGLE_WORKSPACE_TOKEN_BROKER_URL is unset.
Common situations: Self-hosting the OpenWork server and forgetting to export the client secret env var; typos or empty-string env values (whitespace is trimmed, so ' ' counts as missing); migrating deployments where the legacy secret env var name was renamed; pointing the client at a custom OAuth client ID without providing its secret.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Google Workspace refresh token is missing. Reconnect Google
- Google OAuth refresh did not return an access token.
- google_workspace_not_connected
- github_connector_app_not_configured
- MCP_OAUTH_CONFIGURATION_REQUIRED
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/93bdd952804e4c9c.
Report an issue: GitHub.