Skip to content

A lightweight, secure reverse proxy with Google OAuth authentication for OpenCode.

License

Notifications You must be signed in to change notification settings

MILCGroup/opencode-gateway

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

OpenCode Gateway

A lightweight, secure reverse proxy with Google OAuth authentication for OpenCode. Protects your OpenCode server by enforcing authentication before proxying requests.

Note: This project is not built by the OpenCode team and is not affiliated with OpenCode in any way.

Bun TypeScript License

✨ Features

  • πŸ” Google OAuth 2.0 - PKCE flow for secure authentication
  • πŸͺ Session Management - HMAC-signed secure session cookies
  • πŸ”„ Reverse Proxy - Seamless forwarding to upstream OpenCode server
  • 🌐 WebSocket Support - Full WebSocket proxying with authentication
  • πŸ“‘ SSE Streaming - Real-time log streaming with automatic reconnection
  • πŸ₯ Health Checks - Built-in health monitoring endpoints
  • πŸ› οΈ Debug Tools - Log viewer UI and SSE test tools
  • πŸ—οΈ Modular Architecture - Clean, maintainable, testable codebase

πŸš€ Quick Start

Prerequisites

  • Bun >= 1.0.0
  • Google OAuth credentials (Client ID and Secret)
  • OpenCode server running (for proxying)

Installation

  1. Install dependencies:

    bun install
  2. Create .env file:

    SESSION_SECRET=your-very-long-secret-key-at-least-32-characters
    GOOGLE_REDIRECT_CLIENT_ID=your-client-id
    GOOGLE_REDIRECT_CLIENT_SECRET=your-client-secret
    GOOGLE_REDIRECT_URI=http://localhost:4096/auth/google/callback
    PORT=4096
    TARGET_HOST=127.0.0.1
    TARGET_PORT=4097
  3. Run the server:

    bun run dev    # Development with watch
    bun run start  # Production
  4. Authenticate:

    • Visit http://localhost:4096/auth/google/start
    • Complete Google OAuth flow
    • You'll be redirected back with a session cookie

πŸ”§ Configuration

Environment Variables

Variable Required Default Description
SESSION_SECRET βœ… - Secret key for session signing (min 32 chars recommended)
GOOGLE_REDIRECT_CLIENT_ID βœ… - Google OAuth Client ID
GOOGLE_REDIRECT_CLIENT_SECRET βœ… - Google OAuth Client Secret
GOOGLE_REDIRECT_URI βœ… http://localhost:4096/auth/google/callback OAuth redirect URI
PORT ❌ 4096 Proxy server port
TARGET_HOST ❌ 127.0.0.1 Upstream OpenCode server host
TARGET_PORT ❌ 4097 Upstream OpenCode server port
TOKEN_PATH ❌ ~/.opencode-gateway/google-auth.json Token storage path
SESSION_COOKIE_NAME ❌ opencode_session Session cookie name
COOKIE_SECURE ❌ Auto-detect Use secure cookies (HTTPS)
PROXY_TO_SERVER_SECRET ❌ - Optional secret for upstream authentication
TRUST_PROXY ❌ false Trust proxy headers (X-Forwarded-*)

Example .env File

# Required
SESSION_SECRET=your-very-long-secret-key-at-least-32-characters-long
GOOGLE_REDIRECT_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_REDIRECT_CLIENT_SECRET=your-google-client-secret

# Optional - defaults shown
GOOGLE_REDIRECT_URI=http://localhost:4096/auth/google/callback
PORT=4096
TARGET_HOST=127.0.0.1
TARGET_PORT=4097
TOKEN_PATH=~/.opencode-gateway/google-auth.json
SESSION_COOKIE_NAME=opencode_session
COOKIE_SECURE=true
TRUST_PROXY=false

🌐 API Endpoints

Public Endpoints

Endpoint Method Description
/health GET Health check
/global/health GET Global health check
/auth/google/start GET Begin OAuth flow (query: ?project=<id>)
/auth/google/callback GET OAuth callback
/auth/google/config GET OAuth configuration info
/debug/sse-test GET SSE test UI
/debug/sse GET SSE test endpoint

Authenticated Endpoints

Endpoint Method Description
/ * Proxied to upstream OpenCode server
/auth/google/token GET Get stored OAuth token
/logs GET Log viewer UI (HTML) or log streaming (SSE)
/logs/stream GET Log streaming (SSE) to /global/event

πŸ”„ How It Works

  1. User visits /auth/google/start β†’ Redirected to Google OAuth
  2. Google redirects back to /auth/google/callback with authorization code
  3. Proxy exchanges code for tokens using PKCE verification
  4. Tokens stored locally and secure session cookie set
  5. Subsequent requests with valid session cookie are proxied to OpenCode

Authentication Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Browser β”‚ ──────> β”‚  Proxy   β”‚ ──────> β”‚ Google  β”‚ ──────> β”‚   Proxy     β”‚
β”‚         β”‚ <────── β”‚          β”‚ <────── β”‚  OAuth  β”‚ <────── β”‚  (callback) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚                    β”‚                                           β”‚
     β”‚                    β”‚                                           β”‚
     β”‚                    β–Ό                                           β–Ό
     β”‚              [Session Cookie]                            [Store Tokens]
     β”‚                    β”‚                                           β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
                          β–Ό
                   [Authenticated Requests]
                          β”‚
                          β–Ό
                   [OpenCode Server]

πŸ“‘ Log Streaming

The proxy provides real-time log streaming via Server-Sent Events (SSE).

Web UI

Visit http://localhost:4096/logs after authenticating for a terminal-style log viewer with:

  • Real-time log streaming
  • Color-coded log levels
  • Auto-scroll to latest entries
  • Clear logs functionality

API Usage

const eventSource = new EventSource('/logs/stream', { 
  withCredentials: true 
})

eventSource.onmessage = (event) => {
  const logEntry = JSON.parse(event.data)
  console.log(logEntry)
}

eventSource.onerror = (error) => {
  console.error('SSE connection error:', error)
}

Features

  • βœ… Automatic reconnection on connection loss
  • βœ… Real-time log streaming
  • βœ… Structured log format
  • βœ… Supports Last-Event-ID for reconnection

πŸ—οΈ Architecture

The proxy uses a modular architecture with clear separation of concerns:

src/
β”œβ”€β”€ core/          # Pure logic (auth, session, proxy decisions)
β”œβ”€β”€ adapters/      # Runtime implementations (logger, storage, proxy)
β”œβ”€β”€ middleware/    # High-level coordination (auth flow)
└── views/         # HTML templates

Key Design Patterns

  • RequestContext Pattern: Dependency injection for testability
  • Core/Adapters Separation: Pure logic vs side effects
  • Zero Duplication: All shared logic in reusable modules

πŸ§ͺ Development

Project Structure

opencode-gateway/
β”œβ”€β”€ proxy.ts                    # Main entry point
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ types.ts                # Type definitions
β”‚   β”œβ”€β”€ config.ts               # Configuration loader
β”‚   β”œβ”€β”€ core/                   # Pure logic modules
β”‚   β”‚   β”œβ”€β”€ auth.ts             # OAuth & PKCE
β”‚   β”‚   β”œβ”€β”€ session.ts          # Session management
β”‚   β”‚   β”œβ”€β”€ proxy.ts            # Proxy logic
β”‚   β”‚   β”œβ”€β”€ headers.ts          # Security headers
β”‚   β”‚   └── http-utils.ts       # HTTP utilities
β”‚   β”œβ”€β”€ adapters/               # Implementations
β”‚   β”‚   β”œβ”€β”€ logger/             # Logging adapters
β”‚   β”‚   β”œβ”€β”€ storage/            # Token storage
β”‚   β”‚   └── proxy/              # Proxy server
β”‚   β”œβ”€β”€ middleware/             # Coordination
β”‚   β”‚   └── auth-flow.ts        # Auth flow
β”‚   └── views/                  # HTML templates
└── tests/                      # Test suite

Running Tests

bun test

The test suite includes unit tests for core modules (auth, session, config, http-utils) with test helpers for RequestContext mocking.

πŸ”’ Security

Features

  • βœ… PKCE Flow: Prevents authorization code interception
  • βœ… HMAC Sessions: Tamper-proof session cookies
  • βœ… State TTL: OAuth state expires after 10 minutes
  • βœ… Secret Validation: Warnings for weak secrets
  • βœ… Hop-by-Hop Headers: Proper header stripping
  • βœ… Security Headers: HSTS, CSP, X-Frame-Options

Best Practices

  1. Use strong secrets: At least 32 characters for SESSION_SECRET
  2. HTTPS in production: Set COOKIE_SECURE=true for HTTPS
  3. Environment variables: Store secrets in .env, not in code
  4. Token storage: Keep token file secure (default: ~/.opencode-gateway/)

πŸ› Troubleshooting

"SESSION_SECRET is required"

  • Ensure .env has SESSION_SECRET set
  • Or set it as an environment variable
  • Minimum 32 characters recommended

"Google OAuth credentials are required"

  • Check GOOGLE_REDIRECT_CLIENT_ID and GOOGLE_REDIRECT_CLIENT_SECRET
  • Verify credentials in Google Cloud Console
  • Ensure redirect URI matches exactly

WebSocket connections not working

  • Ensure session cookie is sent with upgrade request
  • Check that upstream server supports WebSocket
  • Verify proxy is handling upgrade requests correctly

Can't connect to upstream

  • Verify TARGET_HOST and TARGET_PORT are correct
  • Ensure OpenCode server is running
  • Check firewall/network settings

🀝 Contributing

This is a focused project, but improvements are welcome! Key areas:

  • Integration tests
  • Additional storage adapters
  • Performance optimizations
  • Documentation improvements

See CONTRIBUTING.md for guidelines.

πŸ“„ License

MIT License - see LICENSE file for details

πŸ™ Acknowledgments

Built with:

About

A lightweight, secure reverse proxy with Google OAuth authentication for OpenCode.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published