This is the production source code for the Bindify API — an MCP authentication proxy that connects AI assistants to third-party services like Linear, Todoist, GitHub, Atlassian, Notion, and Figma.
Bindify handles MCP requests on behalf of users. Our security page states that we don't log or store request payloads. Rather than asking you to trust that claim, we publish the code so you can verify it yourself.
This is the exact code deployed to production at api.bindify.dev.
The worker runs on Cloudflare Workers and handles:
- MCP Proxy — Forwards MCP requests to upstream services via secret URLs or API keys. Request payloads pass through but are never logged or stored. See
src/proxy/handler.ts. - Token Encryption — OAuth tokens are encrypted at rest using AES-256-GCM. In zero-knowledge mode, the decryption key is part of the user's secret URL and never stored on our servers. See
src/crypto.ts. - Secret Scrubbing — All structured logs are scrubbed to prevent accidental secret exposure. API keys, bearer tokens, and encrypted payloads are automatically redacted. See
src/logger.ts. - OAuth Flows — Handles authorization and callback flows for each supported service. See
src/services/. - Billing — Stripe integration for subscriptions. See
src/billing/. - Auth — Clerk JWT verification with lazy user provisioning. See
src/auth/.
- Client sends MCP request to
https://api.bindify.dev/mcp/{service}/{credentials} - Worker validates the credentials (API key or secret URL segments)
- Worker decrypts the stored OAuth token (or uses the API key directly)
- Worker forwards the request to the upstream MCP server
- Worker streams the response back to the client
- No request or response payloads are logged at any point
- D1 (SQLite) — User accounts, connections (metadata only), subscriptions, events
- KV — Encrypted token blobs, rate limit counters, blocklist cache
- No request payload storage — Proxied data is forwarded and discarded
| Property | Implementation | Code |
|---|---|---|
| No payload logging | Proxy forwards without logging body | src/proxy/handler.ts |
| Secret scrubbing | Logger redacts API keys, tokens, credentials | src/logger.ts |
| Zero-knowledge encryption | Secret2 never stored; used as AES-256-GCM key | src/crypto.ts |
| Managed encryption | Versioned master keys with HKDF key derivation | src/crypto.ts |
| Token refresh | Automatic cron-based refresh with locking | src/scheduler.ts |
- Node.js 20+
- A Cloudflare account (free tier works)
- OAuth app credentials for the services you want to test
# Install dependencies
npm install
# Copy the example env file and fill in your values
cp .dev.vars.example .dev.vars
# Create a local D1 database and run migrations
npx wrangler d1 migrations apply your-db-name --local
# Copy and configure wrangler.toml from the example
cp wrangler.toml.example wrangler.toml
# Edit wrangler.toml with your Cloudflare account ID and resource IDs
# Start the dev server
npm run devnpm test # Run all tests
npm run test:watch # Watch modeTests use Miniflare (local Cloudflare Workers simulation) with mock bindings — no real credentials needed.
See .dev.vars.example for the full list with descriptions. Key groups:
| Group | Variables | Required |
|---|---|---|
| Auth (Clerk) | CLERK_PUBLISHABLE_KEY, CLERK_JWKS_URL, CLERK_SECRET_KEY |
Yes |
| Billing (Stripe) | STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_CONNECTIONS |
Yes |
| Encryption | MANAGED_ENCRYPTION_KEYS or MANAGED_ENCRYPTION_MASTER_KEY |
Yes |
| CORS | ADMIN_URL |
Yes |
| OAuth Providers | {SERVICE}_CLIENT_ID, {SERVICE}_CLIENT_SECRET |
Per service |
SMTP2GO_API_KEY, ADMIN_NOTIFICATION_EMAIL |
No | |
| Zoho Desk | ZOHO_CLIENT_ID, ZOHO_CLIENT_SECRET, etc. |
No |
Managed-mode connections encrypt tokens with master keys identified by fingerprint (first 16 hex chars of SHA-256 of the key material). Rotate keys every 90 days or after any personnel change with key access.
Frequency: Every 90 days, or immediately after:
- Any team member with key access leaves the organization
- A suspected key compromise
- Any security incident involving the encryption infrastructure
Quick rotation:
npm run rotate-keys -- --keys-file /secure/path/keys.json --env productionThe script generates a new key (or uses one you've pre-added to keys.json), validates it against the live worker, updates the Cloudflare secret, and re-encrypts all managed connections. See the operator runbook in the monorepo at docs/runbooks/key-rotation.md for detailed steps and troubleshooting.
Key generation only:
npm run generate-keyHow it works:
- Keys are stored in
MANAGED_ENCRYPTION_KEYSas a JSON array:[{"key":"<hex>"}] - Each key's fingerprint is computed automatically (SHA-256 prefix)
- The active key is the last entry in the array
- The rotation script communicates with the worker via D1 — no public HTTP endpoints
- The worker's cron handler validates every minute that all connection fingerprints have matching keys in config, logging errors for any orphaned fingerprints
Key removal (after rotation completes and all connections have been re-encrypted):
npm run rotate-keys -- --keys-file /secure/path/keys.json --env production --remove <fingerprint>This repo does not deploy directly. It is referenced as a git submodule in the private bindify monorepo, which orchestrates all deployments to ensure correct ordering (migrations before code, coordinated with admin UI and other services).
CI in this repo runs tests only. To deploy changes:
- Push to
mainhere (tests run) - In the monorepo, bump the submodule and push — this triggers the full deployment pipeline
Apache 2.0 — see LICENSE.