Skip to content

Connector auth

Grounded in docs/architecture/connector-tenant-contract.md. The contract’s core idea: two hosts, two jobs, and secrets that never touch docs, chat, or code.

Surface Host Example
App UI / login Tenant host acme.preshos.com
OAuth redirect_uri and webhooks Canonical preshos.com via appBaseUrlFromEnv() (lib/platform/app-base-url.ts) https://preshos.com/...

Never use the tenant hostname for OAuth redirect_uri or webhooks. The canonical host is derived server-side with appBaseUrlFromEnv(). If you are constructing a callback URL from a tenant hostname, that is wrong.

Hostname baseline (WS-0): wildcard *.preshos.com, WorkOS redirect https://*.preshos.com/callback, NEXT_PUBLIC_APP_URL=https://preshos.com.

Tenant host versus canonical host: tenant host serves app UI and login, canonical host serves OAuth callbacks and webhooks

OAuth state carries the org/connection context as an HMAC signed with AUTH_SECRET:

  • State carries orgId/connection, signed, not trusted on sight. Verify the HMAC before acting on anything in it.
  • Slack: cookie Domain suffix contract lives in lib/integrations/slack/package-oauth-cookie.ts. Follow that file for the exact domain behavior.
  • HubSpot: reuses the shared helpers and signs the redirect host into state. The callback verifies it is answering for the host it expects.

Only exact callback paths are allowed, currently:

  • /api/v1/integrations/packages/slack/oauth/callback
  • /api/v1/integrations/packages/hubspot/oauth/callback

A new package’s callback path must be added to the allowlist in proxy.ts or the callback is rejected. Exact match: no prefixes, no wildcards, no “close enough.”

  • Tenant Vault (ai.secret_grant): per-tenant secret grants. The credential holder provisions through the product flow; code references the grant, never the value.
  • GCP Secret Manager: platform-side secrets (for example, signing keys like AUTH_SECRET).
  • Rotation/expiry handling per connector: not in pasted sources. Confirm in the product repo before documenting.
  • redirect_uri and webhooks use canonical host via appBaseUrlFromEnv(). Grep for tenant-hostname construction and remove it.
  • OAuth state HMAC-verified with AUTH_SECRET before use; carries org/connection
  • Package callback path added to the proxy.ts allowlist (exact path)
  • Slack: cookie domain follows package-oauth-cookie.ts; HubSpot: redirect host signed into state
  • Secrets referenced as grants (Tenant Vault) or SM references. No values in code, tests, fixtures, or docs.
  • Credential provided by the holder through the product flow (never docs or chat)
  • Verified in a scoped test session before real work, in this order: read, draft, gated execute
  • Environment tool list shows exactly the intended tools
  • Binding coordinates recorded: org, package, connection