Skip to content
Back to skills

Google Oauth Integration

ASecurity

Complete Google OAuth integration architecture including token storage and debugging

  • 666 stars
  • 0 votes
  • 1 copy
  • 5 views
  • Added February 8, 2026
developmenttypescriptgobashdebuggingapidatabase

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned February 10, 2026

npx -y skills add majiayu000/claude-skill-registry --skill google-oauth-integration --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Google Oauth Integration?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Google Oauth Integration
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-google-oauth-integration/badge)](https://www.skillsdirectory.com/skills/majiayu000-google-oauth-integration)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: google-oauth-integration
description: 'Complete Google OAuth integration architecture including token storage and debugging'
---

# Google OAuth Integration

This skill documents the complete Google OAuth integration architecture in Orient, including token storage, tool registration, and debugging procedures.

## Triggers

Use this skill when:

- Setting up Google OAuth for a new package or service
- Debugging "Unknown tool" errors for Google tools (Calendar, Gmail, Tasks)
- Understanding token storage and refresh mechanics
- Adding new Google service tools to the ToolExecutorRegistry

## Token Storage Architecture

### Token File Location

Google OAuth tokens are stored in JSON files at:

```
{cwd}/data/oauth-tokens/google-oauth.json
```

**CRITICAL**: The path is resolved using `process.cwd()`, meaning different packages look in different locations:

- Dashboard: `packages/dashboard/data/oauth-tokens/google-oauth.json`
- Slack bot: `packages/bot-slack/data/oauth-tokens/google-oauth.json`
- WhatsApp bot: `packages/bot-whatsapp/data/oauth-tokens/google-oauth.json`
- Project root: `data/oauth-tokens/google-oauth.json`

### Symlink Setup (Required for Multi-Package Access)

Since the dashboard is typically where users connect their Google accounts, other packages need symlinks to access the same tokens:

```bash
# For bot-slack
mkdir -p packages/bot-slack/data/oauth-tokens
ln -sf $(pwd)/packages/dashboard/data/oauth-tokens/google-oauth.json \
       packages/bot-slack/data/oauth-tokens/google-oauth.json

# For bot-whatsapp
mkdir -p packages/bot-whatsapp/data/oauth-tokens
ln -sf $(pwd)/packages/dashboard/data/oauth-tokens/google-oauth.json \
       packages/bot-whatsapp/data/oauth-tokens/google-oauth.json

# For project root (used by MCP servers)
mkdir -p data/oauth-tokens
ln -sf $(pwd)/packages/dashboard/data/oauth-tokens/google-oauth.json \
       data/oauth-tokens/google-oauth.json
```

### Token File Structure

```json
{
  "accounts": {
    "user@gmail.com": {
      "email": "user@gmail.com",
      "displayName": "User Name",
      "accessToken": "ya29...",
      "refreshToken": "1//...",
      "expiresAt": 1768578677699,
      "scopes": [
        "https://www.googleapis.com/auth/calendar",
        "https://www.googleapis.com/auth/gmail.modify"
      ],
      "connectedAt": 1768552923717,
      "lastRefreshAt": 1768575078699
    }
  },
  "pendingStates": {}
}
```

## Environment Variables

Required environment variables in `.env`:

```bash
# OAuth Client Credentials (from Google Cloud Console)
GOOGLE_OAUTH_CLIENT_ID=<your-client-id>.apps.googleusercontent.com
GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-<your-secret>

# Callback URL (must match Google Cloud Console)
GOOGLE_OAUTH_CALLBACK_URL=http://localhost/api/auth/google/callback
```

The OAuth service loads credentials in this priority order:

1. Secrets database (`GOOGLE_OAUTH_CLIENT_ID`, `GOOGLE_OAUTH_CLIENT_SECRET`)
2. Environment variables
3. Credentials file: `credentials/client_secret_*.json`

## Tool Registration Architecture

### Two Registration Systems

Orient has two tool registration systems:

1. **ToolRegistry** (Discovery only)
   - Location: `packages/agents/src/services/toolRegistry.ts`
   - Used by: `discover_tools` for listing available tools
   - Does NOT execute tools

2. **ToolExecutorRegistry** (Execution)
   - Location: `packages/agents/src/services/toolRegistry.ts`
   - Used by: `executeToolCallFromRegistry()` in `packages/mcp-servers/src/tool-executor.ts`
   - Actually runs the tool code

### Registering New Google Tools

To add a new Google tool, register it in the `registerGoogleToolHandlers()` function:

```typescript
// In packages/agents/src/services/toolRegistry.ts

function registerGoogleToolHandlers(registry: ToolExecutorRegistry): void {
  const registerHandlers = async () => {
    const { getCalendarService, getGoogleOAuthService } =
      await import('@orientbot/integrations/google');

    // Register handler
    registry.registerHandler('google_calendar_list_events', async (args) => {
      const calendar = getCalendarService();
      const events = await calendar.listEvents(options, accountEmail);
      return createToolResult(JSON.stringify(events, null, 2));
    });
  };

  void registerHandlers();
}
```

### Legacy vs Modern Registration

| Aspect   | Legacy (mcp-server.ts)                   | Modern (ToolExecutorRegistry)                  |
| -------- | ---------------------------------------- | ---------------------------------------------- |
| Location | `packages/mcp-servers/src/mcp-server.ts` | `packages/agents/src/services/toolRegistry.ts` |
| Pattern  | Giant switch statement                   | Handler registration                           |
| Used by  | Direct MCP server                        | assistant-server via base-server               |
| Status   | Deprecated                               | Preferred                                      |

**Important**: The assistant-server (used by Slack/WhatsApp bots) uses `base-server.ts` which ONLY uses `ToolExecutorRegistry`. It does NOT fall back to the legacy switch statement unless `setLegacyExecutor()` is called.

## Token Refresh Mechanics

The OAuth service in `packages/integrations/src/google/oauth.ts` handles automatic token refresh:

```typescript
async getAuthClient(email: string): Promise<Auth.OAuth2Client> {
  const account = this.data.accounts[email];

  // Check if token needs refresh (expired or expiring in < 5 min)
  if (Date.now() > account.expiresAt - 5 * 60 * 1000) {
    const { credentials } = await client.refreshAccessToken();
    account.accessToken = credentials.access_token;
    account.expiresAt = credentials.expiry_date;
    this.saveData();
  }

  return client;
}
```

Key points:

- Tokens are refreshed automatically 5 minutes before expiration
- Requires valid `refresh_token` from initial OAuth consent
- Requires OAuth credentials (client ID/secret) to be accessible

## Debugging "Unknown Tool" Errors

When Google tools return `{"error":"Unknown tool: google_calendar_list_events"}`:

### Step 1: Check Tool Discovery

```bash
# Tool should appear in discover_tools output
curl -X POST http://localhost:4099/... -d '{"tool":"discover_tools","args":{"mode":"search","query":"calendar"}}'
```

If tool appears in discovery but not execution, it's registered in ToolRegistry but not ToolExecutorRegistry.

### Step 2: Check ToolExecutorRegistry Registration

Look for the tool in `packages/agents/src/services/toolRegistry.ts`:

```typescript
// Should see this in registerGoogleToolHandlers():
registry.registerHandler('google_calendar_list_events', async (args) => { ... });
```

### Step 3: Verify Build and Restart

```bash
# Rebuild affected packages
pnpm --filter @orientbot/agents build
pnpm --filter @orientbot/mcp-servers build

# Copy to root dist (used by OpenCode)
cp packages/mcp-servers/dist/*.js dist/mcp-servers/

# Kill existing MCP server processes
ps aux | grep "assistant-server\|coding-server" | grep -v grep | awk '{print $2}' | xargs kill

# OpenCode will spawn fresh processes on next tool call
```

### Step 4: Check MCP Server Logs

```bash
tail -f logs/mcp-debug-*.log | grep -i "calendar\|google\|unknown"
```

Look for:

- `"Registered tool"` - Tool was registered
- `"Unknown tool"` - Tool not found in any executor
- Error messages during handler registration

## Common Issues

### Issue: Tokens not found

**Symptom**: "No Google account connected"
**Cause**: Token file not found at CWD path
**Fix**: Create symlinks as documented above

### Issue: Token refresh fails

**Symptom**: "Failed to refresh token"
**Cause**: OAuth credentials not accessible
**Fix**: Ensure GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET are set

### Issue: Tool returns "Unknown tool"

**Symptom**: `{"error":"Unknown tool: google_calendar_list_events"}`
**Cause**: Tool not registered in ToolExecutorRegistry
**Fix**: Add handler in `registerGoogleToolHandlers()` and rebuild

### Issue: Stale MCP server

**Symptom**: Changes not taking effect
**Cause**: Old MCP server process still running
**Fix**: Kill old processes, OpenCode will spawn new ones

## Files Reference

| File                                           | Purpose                                 |
| ---------------------------------------------- | --------------------------------------- |
| `packages/integrations/src/google/oauth.ts`    | OAuth service, token storage            |
| `packages/integrations/src/google/calendar.ts` | Calendar service implementation         |
| `packages/agents/src/services/toolRegistry.ts` | Tool discovery + executor registration  |
| `packages/mcp-servers/src/tool-executor.ts`    | Tool execution entry point              |
| `packages/mcp-servers/src/base-server.ts`      | MCP server using executor registry      |
| `packages/mcp-servers/src/mcp-server.ts`       | Legacy MCP server with switch statement |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.