OAuth & secrets runbook — Google marketing plane

Copy Markdown View Source

Credentials for MCP (:noizu_google_mcp) and the OpenTofu provider (noizu/google-marketing). Never commit tokens.

1. GCP project (Plane A)

  1. Create or reuse a GCP project for marketing automation.
  2. Enable APIs:
    • Search Console API (webmasters)
    • Google Analytics Admin API
    • Google Analytics Data API
    • AdSense Management API
    • Google Ads API
  3. Configure OAuth consent screen (Internal or External as appropriate).
  4. Create OAuth client credentials: Desktop app or Web with a localhost redirect for CLI bootstrap.

2. Scopes

Recommended offline scope set (narrow in production):

https://www.googleapis.com/auth/webmasters
https://www.googleapis.com/auth/analytics.edit
https://www.googleapis.com/auth/analytics.readonly
https://www.googleapis.com/auth/adsense.readonly
https://www.googleapis.com/auth/adwords

Elixir helper:

Noizu.Google.Scopes.marketing_default()

3. Bootstrap refresh token (once)

Preferred: CLI

export GOOGLE_CLIENT_ID=...          # Desktop OAuth client for marketing APIs
export GOOGLE_CLIENT_SECRET=...
# Optional dedicated marketing client under google.marketing.* later

# Interactive (prints authorize URL, prompts for code, writes via dc):
bash terraform/marketing/scripts/bootstrap-oauth.sh

# Or step-by-step from Portfolio/Libs/api/elixir-google:
mix google.oauth.authorize
mix google.oauth.exchange --code 'CODE' --write-dc

--write-dc stores secrets google.marketing.{client_id,client_secret,refresh_token} without printing the refresh token.

Manual (iex)

# iex -S mix  (from Portfolio/Libs/api/elixir-google)
url =
  Noizu.Google.OAuth.authorize_url(
    client_id: System.fetch_env!("GOOGLE_CLIENT_ID"),
    redirect_uri: "http://127.0.0.1:8080/oauth2callback",
    scope: Noizu.Google.Scopes.marketing_default(),
    access_type: "offline",
    prompt: "consent"
  )

IO.puts(url)
# Open URL, complete consent, capture ?code=

{:ok, tokens} =
  Noizu.Google.OAuth.token(
    code: "CODE_FROM_REDIRECT",
    redirect_uri: "http://127.0.0.1:8080/oauth2callback",
    client_id: System.fetch_env!("GOOGLE_CLIENT_ID"),
    client_secret: System.fetch_env!("GOOGLE_CLIENT_SECRET")
  )

# tokens["refresh_token"], tokens["access_token"]

Store refresh_token, client_id, client_secret in Infisical / dc (not git).

dc (source of truth for local)

dc config set secrets google.marketing.client_id --value '...'
dc config set secrets google.marketing.client_secret --value '...'
dc config set secrets google.marketing.refresh_token --value '...'
dc config set secrets google.marketing.ads_developer_token --value '...'
# optional MCC:
dc config set secrets google.marketing.ads_login_customer_id --value '...'

Infisical (declared in .infisical-secrets.yaml)

Section id: marketing-google → path /marketing/google
(Separate from Mautic /marketing so keys are not pulled into marketing-app-secrets.)

infisical-populate-secrets --include marketing-google
Infisical keydc path
OAUTH_CLIENT_IDsecrets google.marketing.client_id
OAUTH_CLIENT_SECRETsecrets google.marketing.client_secret
OAUTH_REFRESH_TOKENsecrets google.marketing.refresh_token
ADS_DEVELOPER_TOKENsecrets google.marketing.ads_developer_token
ADS_LOGIN_CUSTOMER_IDsecrets google.marketing.ads_login_customer_id

Load into a shell without printing values:

eval "$(bash terraform/marketing/scripts/load-env.sh)"

4. Environment variables

VariableUsed by
GOOGLE_ACCESS_TOKENSDK, MCP, TF (short-lived)
GOOGLE_MARKETING_ACCESS_TOKENPreferred alias for MCP/TF
GOOGLE_REFRESH_TOKENMCP via Client.ensure_access_token/1
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETRefresh
GOOGLE_ADS_DEVELOPER_TOKENAds API (MCP + TF ads resources)
GOOGLE_ADS_LOGIN_CUSTOMER_IDMCC

MCP also accepts GOOGLE_MARKETING_REFRESH_TOKEN / _CLIENT_ID / _CLIENT_SECRET.

5. MCP

cd Portfolio/Libs/ai/elixir-google-mcp
export GOOGLE_ACCESS_TOKEN=...   # or refresh trio
export GOOGLE_ADS_DEVELOPER_TOKEN=...  # for Ads tools
mix run --no-halt

6. Terraform provider

Portfolio/Libs/api/terraform-provider-google-marketing/scripts/build-provider.sh
export GOOGLE_MARKETING_ACCESS_TOKEN=...
export GOOGLE_ADS_DEVELOPER_TOKEN=...   # for conversion actions
cd terraform/marketing
terragrunt plan

7. Google Ads extra gates

  • Apply for a developer token in Google Ads API Center.
  • For MCC: set login-customer-id / GOOGLE_ADS_LOGIN_CUSTOMER_ID.
  • Conversion actions and mutates need Ads API access on the customer.

8. Safety

  • Ads mutates in MCP default to dry_run=true (validateOnly).
  • Live mutates require confirm=true.
  • Do not put refresh tokens in .tf files or state intentionally; use env/CI secrets.
  • Campaigns/bids are not Terraform resources.