Skip to main content

Hub API

Entrosity Hub's app is a plain client of a REST API under /api/platform/v1. The full endpoint reference is the Hub API reference, rendered from entrosity-hub.backend/api/openapi.yaml, the spec the Hub's router and request validation are generated from.

Conventions​

  • JSON bodies with snake_case keys; request schemas refuse unknown fields (422). Errors are problem documents with a code (Error codes).
  • Session: POST /auth/login sets the session cookie platform_rt (HttpOnly, SameSite=Strict, path /api/platform/v1/auth, 30 days, rotated on every refresh with reuse detection) and returns a 15-minute access token for the Hub's own API (Authorization: Bearer, audience platform).
  • Cookie routes (/auth/refresh, /auth/logout, /auth/product-token, /auth/step-up) accept only requests from the Hub's own origin: a browser's Sec-Fetch-Site must be same-origin, or its Origin the Hub's (PLATFORM_PUBLIC_URL). Sibling hosts of the same site are refused.
  • Access: every route has a rule in entrosity-hub.backend/internal/http/api/access.go: public, session cookie, signed in, organization admin (organization routes answer 404 to anyone who is not an admin of that organization or a platform admin), or platform admin (403 otherwise).
  • Paginated lists take ?page=&page_size= and return items, page, page_size and total.

Tokens for products​

Products never see the session cookie. Their web apps, served on the same host, ask the Hub for short tokens with it:

CallTokenLifetime
POST /auth/product-token {product}Product access token: aud = the product id (rmm), sub = user, sid = session, email, name. No roles: products read them from their copy of the Hub's data. 403 no_product_access without a role in the product, 403 totp_setup_required when an organization requires two-factor authentication and it is not set up.5 minutes
POST /auth/step-up {product, password}Step-up token for one sensitive action (purpose: step-up, single-use jti, bound to user and session). A wrong password is a 422 on password; rate-limited like sign-in.2 minutes

Both calls are read-only for the session (they never rotate the cookie), so they can run while another tab refreshes. Tokens are Ed25519 JWTs (alg: EdDSA) with issuer PLATFORM_PUBLIC_URL and a kid header; the public keys are published at GET /api/platform/v1/.well-known/jwks.json and on the internal listener.

Internal API​

A second listener (PLATFORM_INTERNAL_ADDR) serves products over the private network; Caddy never routes to it.

RouteAuthenticationReturns
GET /internal/v1/jwks.jsonnoneThe signing keys (current and, during a rotation, the previous one).
GET /internal/v1/products/{product}/snapshotAuthorization: Bearer <product token> from PLATFORM_PRODUCT_TOKENS (constant-time compare)Everything the product needs to authorize: users with a role in the product and platform admins (any status), organizations with the product enabled, the product roles, and sessions ended in the last 15 minutes. ETag / If-None-Match answer 304 when nothing changed.

Axis pulls the snapshot every RMM_PLATFORM_SYNC_INTERVAL (Architecture).