Skip to content
Guide Reference Download app

Connections API

@claxedo/connections lets a host link external accounts (Notion, Atlassian, GitHub, Google) once and lets features consume them by capability (docs, work-source, channel, code-host) instead of building their own auth. The host mounts the routes under /api/claxedo/integrations with createIntegrationsRoutes(service, gates).

The Claxedo host mounts these routes behind authRouteOptions(services) plus a loopback check (isLoopbackLocalRequest → 403 in unsigned-local mode). The token and auth-failure endpoints are additionally behind tokenGate, which enforces loopback unconditionally — even in signed mode — plus the x-claxedo-connections: 1 header. The header makes browser reads non-simple/preflighted so the CORS allowlist actually gates them.

All routes are under /api/claxedo/integrations.

Method + pathGates beyond the mountResponse
GET /{ integrations: IntegrationDeclaration[], connections: ConnectionSummary[] }
POST /:id/connectbody { fields, secret, confirmReplace? }, or { method: "oauth", confirmReplace? } with no secret to start an OAuth flow200 { ok: true } · 404 { code: "unknown_integration" } · 409 { code: "connection_exists" } · 422 { code: "connection_verify_failed", reason }
GET /callbacknone — deliberately ungated (the provider redirect lands here from the user’s browser; single-use attempt state + TTL are the guards)HTML landing page, 200 on success / 400 on failure
GET /attempts/:state200 attempt status · 404 { code: "attempt_not_found" }
DELETE /connections/:id200 / 404
POST /connections/:id/reverify200 { ok, reason? }
POST /connections/:id/auth-failuretokenGate: loopback + header x-claxedo-connections: 1 (same gate as the token endpoint)204
GET /connections/:id/token?capability=<x>tokenGate: loopback + header x-claxedo-connections: 1 (else 403); capability granted (else 403)200 frozen shape · 404 · 409 { code: "connection_not_available", status } · 503 { code: "connections_unavailable" } or { code: "connection_refresh_transient" }

GET /connections/:id/token?capability=<x> is how a feature obtains a live token to call a provider API. Consumers request a token per operation and never cache it.

capabilitystringrequired

The capability the caller needs (docs, work-source, channel, code-host). The connection must have that capability granted, or the route returns 403.

x-claxedo-connectionsstringrequired

Must be 1. Missing header returns 403 — this is the tokenGate, which also gates POST /connections/:id/auth-failure and enforces loopback unconditionally (even in signed mode), on top of the auth mount gates.

The success response is the frozen wire shape { token, tokenType, fields? }:

tokenstringrequired

The bearer or basic credential material for one call. For OAuth connections this is the access token only — refresh tokens never cross HTTP.

tokenType"bearer" | "basic"required

How to present the token. Atlassian, for example, returns tokenType: "basic".

fieldsobject

Optional extra fields the provider integration needs alongside the token (present only when the integration declares them).

{
"token": "",
"tokenType": "bearer",
"fields": { "…": "" }
}

Error responses:

  • 404 — unknown connection
  • 409 { code: "connection_not_available", status } — credential not in an available state
  • 503 { code: "connections_unavailable" } — no credential-secret resolver wired
  • 503 { code: "connection_refresh_transient" } — transient OAuth refresh failure; nothing is marked errored, retry the call
  • A connection is an authenticated link to an external account. One connection per integration per host (an explicit replace flow handles re-linking).
  • Capabilities are granted at connect time, derived from what the credential actually covers. Changing grants means reconnecting with broader consent — there is no toggle API.
  • Failure semantics: a definitive provider rejection (invalid_grant-class) marks the credential error and the connection stops serving tokens until the user reconnects or re-verifies; transient failures change nothing and the next call retries. Refresh is single-flight per credential, per-process.

The package ships reference implementations only — Notion, Atlassian, GitHub (key-paste + verify), and Google (OAuth). Additional providers belong in host code, registered via registry.register(decl, impl).


For the storage ports, OAuth attempt machine, and install instructions, see the connections package page.