authentication.md
1 # Authentication Guide 2 3 ## Recommended Setup 4 5 For most users, the one-command setup is the easiest way to get started: 6 7 ```bash 8 # Claude Code users (authentication + MCP + commands + skills + credential guard) 9 mureo setup claude-code 10 11 # Cursor users (authentication + MCP only) 12 mureo setup cursor 13 14 # OpenAI Codex CLI users (MCP + credential guard + workflow skills + shared skills) 15 mureo setup codex 16 17 # Gemini CLI users (extension manifest + MCP) 18 mureo setup gemini 19 20 # CLI-only users (authentication only, terminal prompts) 21 mureo auth setup 22 23 # Browser-based auth wizard — localhost HTML form, no terminal input needed 24 mureo auth setup --web 25 ``` 26 27 ### `--skip-auth` and non-interactive invocation 28 29 Every `mureo setup …` subcommand accepts `--skip-auth`, which installs the MCP config, credential guard, and (where supported) command/skill files without running OAuth. Useful for the double-click installer flow where authentication is handled later via `/onboard` in Claude Code, `$onboard` in Codex, or `mureo auth setup` in a real terminal. 30 31 When `mureo setup …` is invoked from an AI agent's subprocess (Claude Code's Bash tool, Codex, etc.) that has no controlling TTY, `--skip-auth` is implied automatically so the command cannot hang on a `typer.confirm` prompt. A banner in stdout tells the operator to finish authentication in `Terminal.app` afterwards. 32 33 Each subcommand also exposes explicit `--google-ads/--no-google-ads` and `--meta-ads/--no-meta-ads` flags, so you can specify exactly which platforms to configure without any prompt. Passing them alongside `--skip-auth` (or under a non-TTY) emits a warning and is ignored. 34 35 ### `mureo auth setup --web` — browser-based wizard 36 37 Prefer the `--web` flavour when you were pointed to mureo by an AI agent that cannot safely receive terminal input. It starts a short-lived HTTP server on a random localhost port, opens your browser at it, and walks you through Google Ads / Meta Ads credential entry via HTML forms and standard OAuth redirects. Every field in the form has a deep link next to it so you know where to fetch each secret. Security hardening (CSRF rotation, OAuth `state` re-validation, DNS-rebinding guard, localhost-pinned redirect verification, generic error surface, POST size cap, CSP) is described in `SECURITY.md` → "Browser-based auth wizard". 38 39 ## How Credentials Work 40 41 mureo loads credentials from `~/.mureo/credentials.json`, falling back to environment variables if the file is missing or incomplete. 42 43 ## credentials.json Format 44 45 Create `~/.mureo/credentials.json` with the following structure: 46 47 ```json 48 { 49 "google_ads": { 50 "developer_token": "YOUR_DEVELOPER_TOKEN", 51 "client_id": "YOUR_OAUTH_CLIENT_ID", 52 "client_secret": "YOUR_OAUTH_CLIENT_SECRET", 53 "refresh_token": "YOUR_REFRESH_TOKEN", 54 "login_customer_id": "1234567890" 55 }, 56 "meta_ads": { 57 "access_token": "YOUR_ACCESS_TOKEN", 58 "app_id": "YOUR_APP_ID", 59 "app_secret": "YOUR_APP_SECRET" 60 } 61 } 62 ``` 63 64 You can include only the platforms you use. For example, if you only use Google Ads, the `meta_ads` section can be omitted. 65 66 ### Google Ads Fields 67 68 | Field | Required | Description | 69 |-------|----------|-------------| 70 | `developer_token` | Yes | Google Ads API developer token | 71 | `client_id` | Yes | OAuth 2.0 client ID | 72 | `client_secret` | Yes | OAuth 2.0 client secret | 73 | `refresh_token` | Yes | OAuth 2.0 refresh token | 74 | `login_customer_id` | No | Manager account ID (MCC). If omitted, the target `customer_id` is used as fallback. | 75 76 ### Meta Ads Fields 77 78 | Field | Required | Description | 79 |-------|----------|-------------| 80 | `access_token` | Yes | Meta Graph API access token (User or System User token) | 81 | `app_id` | No | Meta App ID | 82 | `app_secret` | No | Meta App Secret | 83 84 ## Environment Variable Fallback 85 86 If `~/.mureo/credentials.json` is missing or lacks the required fields, mureo falls back to environment variables. 87 88 ### Google Ads 89 90 | Variable | Required | Description | 91 |----------|----------|-------------| 92 | `GOOGLE_ADS_DEVELOPER_TOKEN` | Yes | API developer token | 93 | `GOOGLE_ADS_CLIENT_ID` | Yes | OAuth 2.0 client ID | 94 | `GOOGLE_ADS_CLIENT_SECRET` | Yes | OAuth 2.0 client secret | 95 | `GOOGLE_ADS_REFRESH_TOKEN` | Yes | OAuth 2.0 refresh token | 96 | `GOOGLE_ADS_LOGIN_CUSTOMER_ID` | No | Manager account (MCC) customer ID | 97 98 ### Meta Ads 99 100 | Variable | Required | Description | 101 |----------|----------|-------------| 102 | `META_ADS_ACCESS_TOKEN` | Yes | Graph API access token | 103 | `META_ADS_APP_ID` | No | Meta App ID | 104 | `META_ADS_APP_SECRET` | No | Meta App Secret | 105 106 **Resolution order**: credentials.json takes priority. Environment variables are only checked if the corresponding section in credentials.json is missing or incomplete. 107 108 ## Obtaining Google Ads Credentials 109 110 ### 1. Developer Token 111 112 1. Sign in to your Google Ads Manager account at [ads.google.com](https://ads.google.com). 113 2. Navigate to **Tools & Settings > Setup > API Center**. 114 3. If you don't have a developer token, apply for one. For testing, you'll receive a test token immediately. 115 4. Copy the developer token. 116 117 ### 2. OAuth 2.0 Client ID and Secret 118 119 1. Go to the [Google Cloud Console](https://console.cloud.google.com/). 120 2. Create a new project (or select an existing one). 121 3. Enable the **Google Ads API** under **APIs & Services > Library**. 122 4. Navigate to **APIs & Services > Credentials**. 123 5. Click **Create Credentials > OAuth client ID**. 124 6. Select **Desktop app** as the application type. 125 7. Copy the **Client ID** and **Client Secret**. 126 127 ### 3. Refresh Token 128 129 Use the `google-auth-oauthlib` library to obtain a refresh token: 130 131 ```python 132 from google_auth_oauthlib.flow import InstalledAppFlow 133 134 flow = InstalledAppFlow.from_client_config( 135 { 136 "installed": { 137 "client_id": "YOUR_CLIENT_ID", 138 "client_secret": "YOUR_CLIENT_SECRET", 139 "auth_uri": "https://accounts.google.com/o/oauth2/auth", 140 "token_uri": "https://oauth2.googleapis.com/token", 141 } 142 }, 143 scopes=["https://www.googleapis.com/auth/adwords"], 144 ) 145 flow.run_local_server(port=8080) 146 print("Refresh token:", flow.credentials.refresh_token) 147 ``` 148 149 Alternatively, use the [Google OAuth Playground](https://developers.google.com/oauthplayground/) with the `https://www.googleapis.com/auth/adwords` scope. 150 151 ## Obtaining Meta Ads Credentials 152 153 ### Access Token 154 155 **Option A: Graph API Explorer (for testing)** 156 157 1. Go to [Meta Graph API Explorer](https://developers.facebook.com/tools/explorer/). 158 2. Select your app. 159 3. Click **Generate Access Token** with the `ads_management` and `ads_read` permissions. 160 4. The resulting token is short-lived (1-2 hours). 161 162 **Option B: Long-Lived Token (for production)** 163 164 1. Obtain a short-lived user token via the Graph API Explorer. 165 2. Exchange it for a long-lived token (60 days): 166 167 ```bash 168 curl -X GET "https://graph.facebook.com/v21.0/oauth/access_token?\ 169 grant_type=fb_exchange_token&\ 170 client_id=YOUR_APP_ID&\ 171 client_secret=YOUR_APP_SECRET&\ 172 fb_exchange_token=SHORT_LIVED_TOKEN" 173 ``` 174 175 **Option C: System User Token (recommended for automation)** 176 177 1. Go to [Business Settings](https://business.facebook.com/settings/) > **System Users**. 178 2. Create a System User with **Admin** role. 179 3. Assign the ad account to the system user. 180 4. Generate a token with `ads_management` permission. 181 5. System User tokens do not expire. 182 183 ### App ID and App Secret 184 185 1. Go to [Meta for Developers](https://developers.facebook.com/). 186 2. Navigate to your app > **Settings > Basic**. 187 3. Copy the **App ID** and **App Secret**. 188 189 These are optional for basic use, but **required for automatic token refresh** (see below). 190 191 ## Meta Ads Token Auto-Refresh 192 193 mureo can automatically refresh Long-Lived Tokens before they expire, so you never have to manually exchange tokens again. 194 195 ### How It Works 196 197 1. When `mureo auth setup` saves a Meta Ads token, it records a `token_obtained_at` ISO 8601 timestamp in `credentials.json`. 198 2. Each time Meta Ads credentials are loaded, mureo checks the token age. 199 3. If the token is **53+ days old** (7-day safety margin before the 60-day expiry), mureo exchanges it for a fresh Long-Lived Token via the Meta Graph API. 200 4. The new token and timestamp are written back to `credentials.json` atomically. 201 202 ### Requirements 203 204 | Field | Required | Why | 205 |-------|----------|-----| 206 | `app_id` | Yes | Needed for the token exchange API call | 207 | `app_secret` | Yes | Needed for the token exchange API call | 208 | `token_obtained_at` | Auto | Written by `mureo auth setup`; can be added manually (ISO 8601 format) | 209 210 If `app_id` or `app_secret` are missing, auto-refresh is silently skipped and the existing token is used as-is. 211 212 ### credentials.json with auto-refresh fields 213 214 ```json 215 { 216 "meta_ads": { 217 "access_token": "YOUR_ACCESS_TOKEN", 218 "app_id": "YOUR_APP_ID", 219 "app_secret": "YOUR_APP_SECRET", 220 "token_obtained_at": "2025-12-01T00:00:00Z" 221 } 222 } 223 ``` 224 225 ### Safety Features 226 227 - **Concurrent protection** -- an `asyncio.Lock` prevents multiple simultaneous refresh attempts. 228 - **Atomic file write** -- credentials are written to a temp file first, then renamed, to prevent corruption. 229 - **0600 permissions** -- the credentials file is restricted to the owner only. 230 - **Graceful fallback** -- if the refresh fails for any reason (network error, expired app secret, etc.), mureo continues with the existing token and logs a warning. No tool calls are blocked. 231 232 ## Interactive Setup Wizard 233 234 `mureo auth setup` (also called as part of `mureo setup claude-code`) walks you through authentication interactively: 235 236 1. **Google Ads OAuth** -- Enter Developer Token + Client ID/Secret, open browser for OAuth, select account. 237 2. **Meta Ads OAuth** -- Enter App ID/Secret, open browser for OAuth, obtain Long-Lived Token, select account. 238 3. **MCP configuration** -- Choose global (`~/.claude/settings.json`) or project-level (`.mcp.json`). 239 240 ### Project-Level MCP Configuration (`.mcp.json`) 241 242 If you choose project-level placement, `mureo auth setup` creates a `.mcp.json` file in your project root: 243 244 ```json 245 { 246 "mcpServers": { 247 "mureo": { 248 "command": "python", 249 "args": ["-m", "mureo.mcp"] 250 } 251 } 252 } 253 ``` 254 255 AI agents that support `.mcp.json` (e.g., Claude Code) will automatically discover and connect to the mureo MCP server when working in that project directory. 256 257 ## Verifying Credentials 258 259 Use the `mureo auth` commands to verify your setup: 260 261 ```bash 262 # Show authentication status for all platforms 263 mureo auth status 264 265 # Check Google Ads credentials (shows masked values) 266 mureo auth check-google 267 268 # Check Meta Ads credentials (shows masked values) 269 mureo auth check-meta 270 ``` 271 272 Example output for `mureo auth status`: 273 274 ``` 275 === Authentication Status === 276 277 Google Ads: Authenticated 278 Meta Ads: Authenticated 279 ``` 280 281 Example output for `mureo auth check-google`: 282 283 ```json 284 { 285 "developer_token": "***************abcd", 286 "client_id": "123456789.apps.googleusercontent.com", 287 "client_secret": "***************wxyz", 288 "refresh_token": "***************efgh", 289 "login_customer_id": "1234567890" 290 } 291 ``` 292 293 Secrets are masked, showing only the last 4 characters. This lets you verify the right credentials are loaded without exposing them.