Skip to content

New: AI agent integration via Model Context Protocol (MCP).Learn more

GraphQL Gateway

The GraphQL gateway is the single entry point for all frontend GraphQL traffic. It is a custom Hive Router binary written in Rust: the platform compiles its own router executable with the Evolve plugins built in (“bring your own binary” is the Hive Router plugin model). It composes the domain subgraphs into one federated supergraph and handles cross-cutting concerns like authentication, persisted-document enforcement, and observability — with no Node.js runtime in the request path.

Component Source
Hive Router hive-router crate, pinned release tag (see Cargo.toml)
Federated token plugin hive-router-federated-token (own repo, compiled in)
Authoring token plugin in-tree crate (upcoming, ships with the authoring stack)

The service lives in backend/services/graphql-gateway/: src/main.rs registers the plugins against the router entrypoint, router.config.yaml is the production config template, and router.config.local.yaml is used for local development.

The router loads its supergraph from one of two sources:

  • Production: the Hive CDN, polled for updates. Activated by the HIVE_CDN_ENDPOINT + HIVE_CDN_KEY environment variables (the router’s native override turns these into supergraph.source: hive).
  • Development: a local file, supergraph.generated.graphql, composed from the subgraph SDLs with the Hive CLI:
Terminal window
task -d backend/services/graphql-gateway supergraph
# or continuously:
task -d backend/services/graphql-gateway supergraph:watch

The composition task takes a CMS variable (contentful, the default, or storyblok) — the two CMS subgraphs are interchangeable and only differ in which schema.generated.graphql fills the cms slot.

Subgraph Default dev URL Domain
account http://localhost:4001/graphql Authentication & customer data
catalog http://localhost:4002/graphql Products, categories, search
checkout http://localhost:4003/graphql Cart, orders, payments
cms http://localhost:4004/graphql CMS content (Contentful or Storyblok)
order http://localhost:4005/graphql Order history & management
quotes http://localhost:4006/graphql B2B quote requests
Path Purpose
/graphql Main GraphQL endpoint (GET/POST; serves GraphiQL in dev)
/graphql/auth Same GraphQL endpoint on the refresh-cookie path

The router serves any sub-path of the GraphQL endpoint, which is what makes the cookie-path separation work: the refresh-token cookie is scoped to /graphql/auth so it is never sent on regular queries, limiting exposure.

Customer authentication is implemented by the federated_token plugin, a Rust port of the @labdigital/federated-token Apollo plugin. The subgraph wire format is unchanged — subgraphs still receive base64-JSON x-access-token / x-refresh-token headers — so the gateway swap is transparent to every downstream service.

The plugin reads and validates the client’s tokens on each GraphQL request (cookies first, headers as fallback), injects them on outgoing subgraph requests, merges tokens minted or rotated by subgraphs back off their responses, and writes the resulting cookies on the client response. Configuration (issuer, audience, cookie domain, key rotation) lives in the plugins.federated_token block of the router config; the symmetric keys come from FEDERATED_TOKEN_ENCRYPT_KEY_1 / FEDERATED_TOKEN_SIGN_KEY_1.

See Authentication & tokens for token types and the session flow.

The authoring_token plugin (upcoming, part of the authoring stack) resolves the editor’s CMS OAuth token from the __authoring_session cookie or the X-Authoring-Cms-Token header and forwards it to subgraphs. Unlike the customer plugin it never fails a request — enforcement lives in the CMS subgraph’s authoring resolvers.

Trusted-document enforcement is native to Hive Router. In production the persisted_documents config block is enabled with require_id: true: only operations whose documentId is registered in the Hive CDN (App Deployments) are accepted, and arbitrary operations — including introspection — are rejected. There is no bypass header.

In development the block is disabled, because the dev storefront falls back to full queries and there is no local Hive CDN.

Header forwarding to subgraphs is declarative router config (the headers: section of router.config.yaml) — it replaces the custom Apollo data-source code the Node gateway used:

Incoming header Forwarded as Notes
X-StoreContext-StoreKey same Store context, supplied by the storefront
X-StoreContext-Locale same
X-StoreContext-Currency same
X-Forwarded-For X-Client-IP Defaults to 127.0.0.1 locally

See Store context for how services consume these values.

CORS is router config (cors: block). Credentialed requests require explicit origins (never *): local dev allows http://localhost:3000 and the Portless storefront alias; production origins are injected through the CORS_ORIGINS environment variable (a JSON array rendered into the config at container start).

The router exports OpenTelemetry traces and metrics over OTLP. The rest of the stack propagates trace context via B3, and the router matches it — extracting incoming B3 context and injecting B3 toward subgraphs so spans stay in one trace. In production the exporter uses OTLP over HTTP (the collector sits behind an L7 proxy that mangles gRPC trailers); locally it exports to the docker-compose OTel Collector.

Hive Router does not interpolate ${VAR} in its YAML. Two mechanisms fill the gap:

  • Container start: docker-entrypoint.sh renders router.config.yaml with envsubst for an allowlisted set of variables (CORS_ORIGINS, JWT_ISSUER, JWT_AUDIENCE, COOKIE_DOMAIN, the token keys, the OTLP endpoint).
  • Plugin init: the Evolve plugins expand ${VAR} references in their own config blocks at startup, so secrets stay in the environment.

Key environment variables:

Variable Purpose
HIVE_CDN_ENDPOINT / HIVE_CDN_KEY Supergraph source (production)
JWT_ISSUER / JWT_AUDIENCE Token claims validated by the plugins
COOKIE_DOMAIN Cookie domain for auth tokens
FEDERATED_TOKEN_ENCRYPT_KEY_1 / FEDERATED_TOKEN_SIGN_KEY_1 Customer token keys (32 bytes)
CORS_ORIGINS Allowed origins (JSON array, production)
ROUTER_CONFIG_FILE_PATH Which config file to load

pnpm dev (or pnpm dev:backend) runs the gateway via task -d backend/services/graphql-gateway dev, which composes the supergraph and then cargo runs the router on port 4000 against router.config.local.yaml. A Rust toolchain is required. The Taskfile provides working defaults for every secret so the router boots without additional setup.