Skip to content

Commit 6a2e951

Browse files
bokelleyclaude
andauthored
docs: clarify GAM setup with three clear paths and environment validation (#847)
* docs: clarify GAM setup with three clear paths and environment validation Addresses user feedback from first-time setup experience: - Added Path 1 (Mock), Path 2 (GAM OAuth), Path 3 (Service Account) with clear prerequisites - Reorganized .env.template with annotations for each setup path - Added environment validation in Admin UI to warn when GAM OAuth not configured - Service Account now highlighted as recommended when OAuth unavailable - Added GAM prerequisites check script for validation - Enhanced README with MCP testing examples and Claude Desktop integration Key improvements: - Prerequisites documented UPFRONT (no hidden requirements discovered mid-setup) - Test mode now default (no OAuth needed for quick start) - Clear error messages guide users to fix missing configuration - Separation of concerns: Admin UI OAuth vs GAM OAuth clearly explained 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * fix: correct docstring filename in gam_prerequisites_check.py 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 3e5a9c9 commit 6a2e951

File tree

6 files changed

+281
-42
lines changed

6 files changed

+281
-42
lines changed

.env.template

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,76 @@
11
# AdCP Sales Agent - Environment Configuration
22
# =============================================
3-
# Copy this file to .env: cp .env.template .env
4-
# Then edit .env with your actual values.
53
#
4+
# SETUP PATHS:
5+
# Path 1 (Mock/Testing): Set [REQUIRED] variables only
6+
# Path 2 (GAM Local): Set [REQUIRED] + [GAM-OAUTH] variables
7+
# Path 3 (Production): See docs/deployment.md
8+
#
9+
# Copy this file to .env: cp .env.template .env
610
# Docker Compose automatically reads .env - just run: docker-compose up -d
711

812
# ============================================
9-
# REQUIRED - App will not start without these
13+
# [REQUIRED] Essential Configuration
1014
# ============================================
1115

12-
# Gemini API Key (get free key at https://aistudio.google.com/apikey)
16+
# Gemini API Key - Get free key at https://aistudio.google.com/apikey
1317
GEMINI_API_KEY=
1418

15-
# Your email address (grants super admin access)
19+
# Super Admin Email - Your email address for admin access
1620
SUPER_ADMIN_EMAILS=your-email@example.com
1721

1822
# ============================================
19-
# REQUIRED FOR ADMIN UI LOGIN
23+
# [REQUIRED] Admin UI Authentication
2024
# ============================================
21-
# Create OAuth credentials at: https://console.cloud.google.com/apis/credentials
22-
# Add authorized redirect URI: http://localhost:8001/auth/google/callback
25+
# Test Mode is enabled by default for quick start.
26+
# Switch to Google OAuth for production use.
27+
28+
# Test Mode (default - for quick testing)
29+
# Enables pre-configured test accounts: test_super_admin@example.com / test123
30+
# DO NOT USE IN PRODUCTION - set to false and configure OAuth below
31+
ADCP_AUTH_TEST_MODE=true
2332

33+
# Google OAuth (for production use)
34+
# 1. Set ADCP_AUTH_TEST_MODE=false above
35+
# 2. Create OAuth client at: https://console.cloud.google.com/apis/credentials
36+
# 3. Add redirect URI: http://localhost:8001/auth/google/callback
37+
# 4. Enter credentials below:
2438
GOOGLE_CLIENT_ID=
2539
GOOGLE_CLIENT_SECRET=
2640

2741
# ============================================
28-
# OPTIONAL - Defaults work for local development
42+
# [GAM-OAUTH] Google Ad Manager - Path 2 Only
43+
# ============================================
44+
# Required ONLY if using GAM adapter with OAuth authentication
45+
#
46+
# IMPORTANT: These are DIFFERENT from Admin UI credentials above!
47+
# 1. Create separate OAuth client at: https://console.cloud.google.com/apis/credentials
48+
# 2. Add redirect URI: http://localhost:8001/tenant/callback/gam
49+
# 3. Enter credentials below:
50+
# 4. Restart services: docker-compose restart
51+
#
52+
# NOTE: Service Account authentication (recommended for production) can be
53+
# configured via Admin UI and does NOT require these OAuth credentials.
54+
#
55+
GAM_OAUTH_CLIENT_ID=
56+
GAM_OAUTH_CLIENT_SECRET=
57+
58+
# ============================================
59+
# [OPTIONAL] Port Configuration
2960
# ============================================
61+
# Change these if you have port conflicts
3062

31-
# Ports (change if you have conflicts)
3263
POSTGRES_PORT=5432
3364
ADCP_SALES_PORT=8080
3465
ADMIN_UI_PORT=8001
3566
A2A_PORT=8091
3667

37-
# Google Ad Manager integration (only if using GAM adapter)
38-
# GAM_OAUTH_CLIENT_ID=
39-
# GAM_OAUTH_CLIENT_SECRET=
40-
41-
# Allowed admin domains (optional - users from these domains get access)
42-
# SUPER_ADMIN_DOMAINS=example.com
68+
# ============================================
69+
# [OPTIONAL] Advanced Settings
70+
# ============================================
4371

44-
# Environment: development (strict validation) or production (lenient)
72+
# Environment mode: development (strict validation) or production (lenient)
4573
ENVIRONMENT=development
74+
75+
# Allowed admin domains (optional - grant access to all users from these domains)
76+
# SUPER_ADMIN_DOMAINS=example.com

README.md

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,97 @@ The AdCP Sales Agent is a server that:
1111
- **Provides an admin interface** for managing inventory and monitoring campaigns
1212
- **Handles the full campaign lifecycle** from discovery to reporting
1313

14-
## Quick Start
14+
## Quick Start - Choose Your Setup Path
1515

16-
### Docker Setup (Recommended)
16+
### Path 1: Mock Adapter (5 min) - Recommended First Step
17+
18+
**Perfect for:** Learning AdCP, testing integrations, development
1719

1820
```bash
19-
# 1. Clone and enter the repository
21+
# 1. Clone and configure
2022
git clone https://github.com/adcontextprotocol/salesagent.git
2123
cd salesagent
22-
23-
# 2. Create your .env file
2424
cp .env.template .env
25-
# Edit .env with your values (instructions in the file)
25+
26+
# 2. Set your Gemini API key in .env:
27+
# GEMINI_API_KEY=get-free-at-https://aistudio.google.com/apikey
28+
# (Test mode is enabled by default - no OAuth setup needed)
2629

2730
# 3. Start services
2831
docker-compose up -d
2932

30-
# 4. Access the Admin UI
33+
# 4. Create test tenant (note the token output!)
34+
docker-compose exec adcp-server python -m scripts.setup.setup_tenant "Test Publisher" \
35+
--adapter mock \
36+
--admin-email your-email@example.com
37+
38+
# 5. Test the MCP server with AdCP CLI (use token from step 4)
39+
uvx adcp http://localhost:8080/mcp/ --auth YOUR_TOKEN list_tools
40+
41+
# 6. Access Admin UI
3142
open http://localhost:8001
43+
# Login with: test_super_admin@example.com / test123
3244
```
3345

34-
**Required configuration in .env:**
35-
- `GEMINI_API_KEY` - Get free at https://aistudio.google.com/apikey
36-
- `SUPER_ADMIN_EMAILS` - Your email address
37-
- `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` - From [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
38-
- Add redirect URI: `http://localhost:8001/auth/google/callback`
46+
**Using with Claude Desktop:** Add to your Claude config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
47+
```json
48+
{
49+
"mcpServers": {
50+
"adcp": {
51+
"command": "uvx",
52+
"args": ["mcp-remote", "http://localhost:8080/mcp/", "--header", "x-adcp-auth: YOUR_TOKEN"]
53+
}
54+
}
55+
}
56+
```
3957

40-
### Creating Your First Tenant
58+
The mock adapter simulates a complete ad server - no external credentials needed.
4159

42-
```bash
43-
# Create a test tenant with mock adapter (no ad server needed)
44-
docker-compose exec adcp-server python -m scripts.setup.setup_tenant "My Publisher" \
45-
--adapter mock \
46-
--admin-email your-email@example.com
47-
```
60+
---
4861

49-
### Conductor Setup (for parallel workspaces)
62+
### Path 2: Google Ad Manager with OAuth (30 min)
5063

51-
If using Conductor, see [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for workspace setup.
52-
Each workspace gets unique ports automatically.
64+
**Perfect for:** Quick local testing against a real GAM network
65+
66+
**Note:** This uses OAuth refresh tokens. For production, use Service Account authentication instead (see Path 3).
67+
68+
**Prerequisites - complete BEFORE starting:**
69+
70+
1. **Create GAM OAuth Credentials:**
71+
- Go to [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
72+
- Create OAuth 2.0 Client ID (Web application)
73+
- Add redirect URI: `http://localhost:8001/tenant/callback/gam`
74+
- Save Client ID and Client Secret
75+
76+
2. **Add to .env file:**
77+
```bash
78+
GAM_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
79+
GAM_OAUTH_CLIENT_SECRET=your-client-secret
80+
```
81+
82+
3. **Start services and configure:**
83+
```bash
84+
docker-compose up -d
85+
docker-compose exec adcp-server python -m scripts.setup.setup_tenant "My Publisher" \
86+
--adapter google_ad_manager \
87+
--gam-network-code YOUR_NETWORK_CODE \
88+
--admin-email your-email@example.com
89+
```
90+
91+
4. **Complete OAuth flow** in Admin UI at http://localhost:8001
92+
93+
---
94+
95+
### Path 3: Production Deployment
96+
97+
Use **Service Account** authentication (recommended over OAuth):
98+
- Credentials never expire
99+
- Better security and isolation
100+
- No manual refresh required
101+
102+
See [docs/deployment.md](docs/deployment.md) for production setup.
103+
104+
---
53105

54106
### Troubleshooting
55107

@@ -58,8 +110,12 @@ Each workspace gets unique ports automatically.
58110
docker-compose logs admin-ui | head -50 # Check for missing env vars
59111
```
60112

113+
**GAM OAuth error: "Could not determine client ID"?**
114+
- Check that `GAM_OAUTH_CLIENT_ID` and `GAM_OAUTH_CLIENT_SECRET` are set in `.env`
115+
- Run `docker-compose restart` after adding credentials
116+
61117
**OAuth callback 404?**
62-
- Redirect URI must be exactly: `http://localhost:8001/auth/google/callback`
118+
- Redirect URI must match exactly what's in Google Cloud Console
63119

64120
**More help:** See [Troubleshooting Guide](docs/TROUBLESHOOTING.md)
65121

docs/TROUBLESHOOTING.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,52 @@ See `docker-compose.override.example.yml` for complete configuration.
267267

268268
### GAM Integration Issues
269269

270+
#### "Could not determine client ID from request"
271+
272+
**Symptom**: Error when trying to save/test GAM configuration with OAuth authentication.
273+
274+
**Cause**: `GAM_OAUTH_CLIENT_ID` or `GAM_OAUTH_CLIENT_SECRET` environment variables not set.
275+
276+
**Solution**:
277+
278+
1. Check if environment variables are set:
279+
```bash
280+
docker-compose exec adcp-server env | grep GAM_OAUTH
281+
```
282+
283+
2. If missing, add to your `.env` file:
284+
```bash
285+
GAM_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
286+
GAM_OAUTH_CLIENT_SECRET=your-client-secret
287+
```
288+
289+
3. Create OAuth credentials at [Google Cloud Console](https://console.cloud.google.com/apis/credentials):
290+
- Create OAuth 2.0 Client ID (Web application)
291+
- Add redirect URI: `http://localhost:8001/tenant/callback/gam`
292+
293+
4. Restart services:
294+
```bash
295+
docker-compose restart
296+
```
297+
298+
5. Verify configuration:
299+
```bash
300+
docker-compose exec adcp-server python scripts/gam_prerequisites_check.py
301+
```
302+
303+
**Alternative**: Use Service Account authentication instead (no OAuth setup required). Configure via Admin UI in the "Service Account Integration" section.
304+
305+
#### GAM OAuth vs Service Account
306+
307+
| Feature | OAuth (Refresh Token) | Service Account |
308+
|---------|----------------------|-----------------|
309+
| Setup complexity | Higher (requires OAuth credentials) | Lower (just upload JSON key) |
310+
| Token expiration | Tokens can expire | Never expires |
311+
| Use case | Quick local testing | Production deployments |
312+
| Security | Tied to user account | Isolated service identity |
313+
314+
**Recommendation**: Use Service Account for production; OAuth for quick testing only.
315+
270316
#### OAuth Token Invalid
271317
```bash
272318
# Refresh OAuth token

scripts/gam_prerequisites_check.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Check if GAM prerequisites are configured.
4+
5+
Usage:
6+
python scripts/gam_prerequisites_check.py
7+
8+
Returns:
9+
Exit code 0 if all prerequisites met, 1 otherwise
10+
"""
11+
import os
12+
import sys
13+
14+
15+
def main():
16+
"""Check GAM prerequisites and print status."""
17+
print("Checking GAM Prerequisites...\n")
18+
19+
all_good = True
20+
21+
# Check OAuth credentials
22+
client_id = os.environ.get("GAM_OAUTH_CLIENT_ID")
23+
client_secret = os.environ.get("GAM_OAUTH_CLIENT_SECRET")
24+
25+
if client_id:
26+
print(" GAM_OAUTH_CLIENT_ID is set")
27+
else:
28+
print(" GAM_OAUTH_CLIENT_ID is not set")
29+
all_good = False
30+
31+
if client_secret:
32+
print(" GAM_OAUTH_CLIENT_SECRET is set")
33+
else:
34+
print(" GAM_OAUTH_CLIENT_SECRET is not set")
35+
all_good = False
36+
37+
# Check service account provisioning capability
38+
gcp_project = os.environ.get("GCP_PROJECT_ID")
39+
if gcp_project:
40+
print(f" GCP_PROJECT_ID is set ({gcp_project})")
41+
print(" Service account auto-provisioning available")
42+
else:
43+
print(" GCP_PROJECT_ID not set")
44+
print(" Service account auto-provisioning unavailable")
45+
print(" Manual service account upload still supported")
46+
47+
print()
48+
49+
if not all_good:
50+
print("GAM OAuth prerequisites not fully configured\n")
51+
print("To use GAM with OAuth authentication:")
52+
print(" 1. Go to https://console.cloud.google.com/apis/credentials")
53+
print(" 2. Create OAuth 2.0 Client ID (Web application)")
54+
print(" 3. Add redirect URI: http://localhost:8001/tenant/callback/gam")
55+
print(" 4. Set credentials in .env file:")
56+
print(" GAM_OAUTH_CLIENT_ID=your-client-id")
57+
print(" GAM_OAUTH_CLIENT_SECRET=your-client-secret")
58+
print(" 5. Restart: docker-compose restart\n")
59+
print("Alternative: Use Service Account authentication via Admin UI")
60+
print("(No OAuth setup required)\n")
61+
return 1
62+
else:
63+
print("All GAM OAuth prerequisites configured!")
64+
print("You can now use OAuth authentication with GAM.\n")
65+
return 0
66+
67+
68+
if __name__ == "__main__":
69+
sys.exit(main())

src/admin/blueprints/tenants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ def tenant_settings(tenant_id, section=None):
215215
if adapter_config_obj and adapter_config_obj.adapter_type == "google_ad_manager":
216216
oauth_configured = bool(adapter_config_obj.gam_refresh_token)
217217

218+
# Check if GAM OAuth environment variables are configured
219+
gam_oauth_configured = bool(
220+
os.environ.get("GAM_OAUTH_CLIENT_ID") and os.environ.get("GAM_OAUTH_CLIENT_SECRET")
221+
)
222+
218223
# Get advertiser data for the advertisers section
219224
from src.core.database.models import GAMInventory, Principal
220225

@@ -379,6 +384,7 @@ def tenant_settings(tenant_id, section=None):
379384
active_adapter=active_adapter,
380385
adapter_config=adapter_config_dict, # Use dict format
381386
oauth_configured=oauth_configured,
387+
gam_oauth_configured=gam_oauth_configured, # Environment check for GAM OAuth
382388
last_sync_time=last_sync_time,
383389
running_sync=running_sync, # Pass running sync info
384390
principals=principals,

0 commit comments

Comments
 (0)