Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ node_modules/
.DS_Store
/blob-report/
/dist/
/cache/
/cache/
google.json
227 changes: 227 additions & 0 deletions docs/google-service-account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# Google Service Account Setup

## Overview

Google service accounts allow server-to-server authentication without user interaction. Service account credentials are JSON key files that contain a private key for signing requests to Google APIs.

**🚨 TEMPORARY PROOF OF CONCEPT**

The `X-Google-Json` header currently accepts **unencrypted** service account JSON keys. This will be replaced with an encrypted key mechanism soon. Until then, only use for internal testing and local development.

**⚠️ CRITICAL SECURITY WARNING**

Service account keys are **EXTREMELY DANGEROUS**:
- **Keys DO NOT expire** - They remain valid until manually revoked
- **Full access** - Anyone with the key has complete access to resources shared with the service account
- **No user context** - Keys work even if you're not logged in
- **Irreversible access** - Leaked keys can be used immediately by attackers

**DO NOT:**
- ❌ Commit service account keys to version control
- ❌ Send keys via email, Slack, or insecure channels
- ❌ Store keys in client-side applications or public-facing code
- ❌ Use the X-Google-Json API header outside of secure server-to-server environments
- ❌ Share keys with untrusted parties
- ❌ Use this in any production environment

**ONLY USE FOR:**
- ✅ Internal testing and local development
- ✅ Demonstration purposes in secure environments

## Creating a Service Account

### Step 1: Access Google Cloud Console

1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Select your project (or create a new one)
3. Note your project ID for reference

### Step 2: Enable Google Drive API

1. Navigate to **APIs & Services** → **Library**
2. Search for "Google Drive API"
3. Click **Enable**
4. Wait for enablement (~30 seconds)

### Step 3: Create Service Account

1. Navigate to **IAM & Admin** → **Service Accounts**
2. Click **Create Service Account**

3. Fill in details:
- **Service account name**: `cascade-mcp-drive` (or your preferred name)
- **Service account ID**: Auto-generated (e.g., `[email protected]`)
- **Description**: "Service account for CascadeMCP Google Drive integration"

4. Click **Create and Continue**

5. **Grant permissions** (Optional):
- For most use cases, you can skip this step
- Service accounts access only files explicitly shared with them
- If needed, add roles like "Editor" or specific Drive roles

6. Click **Continue**

7. **Grant users access** (Optional):
- Skip this step for typical use cases

8. Click **Done**

### Step 4: Create and Download Key

1. Find your newly created service account in the list
2. Click on the service account email
3. Go to **Keys** tab
4. Click **Add Key** → **Create new key**
5. Select **JSON** format
6. Click **Create**
7. **IMPORTANT**: The JSON file downloads automatically:
- Save it securely immediately
- Rename it to `google.json` (or your preferred name)
- **This is your only chance to download this key**
- If lost, you must create a new key

### Step 5: Secure the Key File

Place the key in your project root and ensure it's ignored by git:

```bash
# Move to project root
mv ~/Downloads/project-id-*.json ./google.json

# Verify .gitignore is working
git status # google.json should NOT appear in untracked files
```

**Add to `.gitignore`** (if not already present):

```gitignore
# Google Service Account Keys
google.json
```

## Service Account JSON Structure

The downloaded JSON file contains:

```json
{
"type": "service_account",
"project_id": "your-project-id",
"private_key_id": "abc123...",
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "123456789...",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/...",
"universe_domain": "googleapis.com"
}
```

**Key fields:**
- `type`: Must be `"service_account"`
- `project_id`: Your Google Cloud project ID
- `private_key`: RSA private key for signing JWT tokens
- `client_email`: Service account email (used to share files)

## Granting Access to Files

Service accounts can only access Google Drive files that are explicitly shared with them:

### Share a File with Service Account

1. Open Google Drive
2. Right-click on a file or folder
3. Click **Share**
4. Enter the service account email:
```
[email protected]
```
5. Set permission level:
- **Viewer**: Read-only access
- **Commenter**: View and comment
- **Editor**: Full edit access
6. Uncheck "Notify people" (service accounts can't receive emails)
7. Click **Share**

**Important Notes:**
- Service accounts appear as regular users in sharing dialogs
- They cannot access files in "My Drive" unless explicitly shared
- Sharing with a service account is the ONLY way it can access files
- Service accounts cannot interact with Google Drive UI

## Testing the Service Account

### Direct Client Test

Test the service account credentials directly:

```bash
node --import ./loader.mjs scripts/api/drive-about-user.ts
```

This will display the service account's email and permission ID.

### API Endpoint Test

**Test with curl:**
```bash
# Make sure server is running: npm run dev

curl -X POST http://localhost:3000/api/drive-about-user \
-H "Content-Type: application/json" \
-H "X-Google-Json: $(cat google.json)" \
-d '{}'
```

**Test with Node.js:**
```javascript
const fs = require('fs');

const serviceAccountJson = fs.readFileSync('./google.json', 'utf-8');

const response = await fetch('http://localhost:3000/api/drive-about-user', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Google-Json': serviceAccountJson,
},
body: JSON.stringify({}),
});

const data = await response.json();
console.log(`User: ${data.user.displayName}`);
console.log(`Email: ${data.user.emailAddress}`);
```

## Revoking Service Account Keys

If a key is compromised or no longer needed:

### Option 1: Delete the Key

1. Go to **IAM & Admin** → **Service Accounts**
2. Click on the service account
3. Go to **Keys** tab
4. Find the key (by Key ID)
5. Click ⋮ (three dots) → **Delete**
6. Confirm deletion

**Effect:** Key becomes invalid immediately and cannot be restored

### Option 2: Delete the Service Account

1. Go to **IAM & Admin** → **Service Accounts**
2. Check the box next to the service account
3. Click **Delete** (trash icon)
4. Confirm deletion

**Effect:** All keys for this service account become invalid, and access to all shared files is revoked

## Related Documentation

- [REST API Documentation](./rest-api.md) - Using service accounts with REST APIs
- [Google Cloud IAM Best Practices](https://cloud.google.com/iam/docs/best-practices)
- [Google Drive API - Service Accounts](https://developers.google.com/identity/protocols/oauth2/service-account)
100 changes: 100 additions & 0 deletions docs/rest-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ X-Anthropic-Token: sk-ant-api03-...
- File content - Read only
- File comments - Read only

**Google Service Account** (for drive-about-user endpoint):

See the [Google Service Account Setup Guide](./google-service-account.md) for detailed instructions with screenshots.

⚠️ **CRITICAL SECURITY WARNING**: Service account keys do NOT expire and provide full access to shared resources. The X-Google-Json header should ONLY be used in secure, server-to-server environments. Never expose this endpoint to client-side applications.

Quick setup:
1. Create service account in [Google Cloud Console](https://console.cloud.google.com/)
2. Enable Google Drive API
3. Create and download JSON key
4. Share Google Drive files with the service account email
5. Use the JSON content in the `X-Google-Json` header

**Anthropic API Key:**
1. Go to https://console.anthropic.com/settings/keys
2. Create an API key
Expand Down Expand Up @@ -287,6 +300,93 @@ while (true) {
console.log(`Total stories written: ${storiesWritten}`);
```

---

### Drive About User (Google Service Account)

Get authenticated user information from Google Drive using service account credentials.

🚨 **TEMPORARY PROOF OF CONCEPT** - The `X-Google-Json` header currently accepts unencrypted service account credentials and will be replaced with an encrypted key mechanism soon. Only use for internal testing and local development. See [Google Service Account Setup Guide](./google-service-account.md) for details.

**Endpoint:** `POST /api/drive-about-user`

**Headers:**
- `Content-Type: application/json`
- `X-Google-Json` (required) - Service account JSON as string

**Request Body:**
```json
{}
```

**Parameters:**
- None (empty request body)

**Success Response (200 OK):**
```json
{
"user": {
"kind": "drive#user",
"displayName": "cascade-mcp-drive",
"emailAddress": "[email protected]",
"permissionId": "12345678901234567890",
"photoLink": "https://lh3.googleusercontent.com/...",
"me": true
}
}
```

**Error Response (401 Unauthorized):**
```json
{
"error": "Missing credentials header",
"details": "Please provide credentials via X-Google-Json header (plaintext service account JSON)"
}
```

**Example using curl:**
```bash
# Load service account JSON from file
# Note: The JSON must be passed as a single-line string in the header
curl -X POST http://localhost:3000/api/drive-about-user \
-H "Content-Type: application/json" \
-H "X-Google-Json: $(cat google.json | tr -d '\n')" \
-d '{}'

# Alternative: Use a variable to avoid shell escaping issues
GOOGLE_JSON=$(cat google.json | tr -d '\n')
curl -X POST http://localhost:3000/api/drive-about-user \
-H "Content-Type: application/json" \
-H "X-Google-Json: $GOOGLE_JSON" \
-d '{}'
```

**Example using Node.js:**
```javascript
const fs = require('fs');

// Load service account JSON
const serviceAccountJson = fs.readFileSync('./google.json', 'utf-8');

const response = await fetch('http://localhost:3000/api/drive-about-user', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Google-Json': serviceAccountJson,
},
body: JSON.stringify({}),
});

const data = await response.json();
console.log(`User: ${data.user.displayName}`);
console.log(`Email: ${data.user.emailAddress}`);
console.log(`Permission ID: ${data.user.permissionId}`);
```

For more information, see the [Google Service Account Setup Guide](./google-service-account.md).

---

## Error Handling

All endpoints return JSON responses with appropriate HTTP status codes:
Expand Down
Loading
Loading