Gateway API Proxy

Call a gateway's HTTP API without holding that gateway's credentials. The proxy authenticates upstream as the gateway's master_rest user, and authorises you by asking the CMS whether you have access to the facility behind it.

1. Get a token

The proxy has no accounts of its own. Log into the CMS and use that token:

TOKEN=$(curl -s https://app.smartrplace.de/api/users/login \
          -H 'Content-Type: application/json' \
          -d '{"email":"you@smartrplace.de","password":"…"}' | jq -r .token)
The CMS wants this token in an Auth-Token header, not Authorization: Bearer — its OpenAPI spec declares a bearer scheme it does not implement. The proxy accepts either form.

2. Call a gateway

curl -H "Auth-Token: $TOKEN" \
     https://gateway-access.smartrplace.de/gw/jakob-sozien/apimobile/monitoring/datapoints

The gateway may be addressed three ways, all equivalent:

FormExample
subdomain/gw/jakob-sozien/…
bare gateway id/gw/19106/…
gw-prefixed id/gw/gw19106/…

Everything after the gateway is the upstream path and is forwarded as written, percent-encoding intact, together with the query string.

3. Or log in once

If holding a CMS token is awkward, exchange the credentials for a session token — the proxy forwards them to the CMS and never stores the password:

TOKEN=$(curl -s https://gateway-access.smartrplace.de/auth/login           -H 'Content-Type: application/json'           -d '{"email":"you@smartrplace.de","password":"…"}' | jq -r .token)
# then use it exactly like a CMS token, in Auth-Token
curl -H "Auth-Token: $TOKEN" https://gateway-access.smartrplace.de/gw/19106/apimobile/monitoring/datapoints
curl -X POST -H "Auth-Token: $TOKEN" https://gateway-access.smartrplace.de/auth/logout      # when done

Sessions last 8 hours. They grant nothing extra: the identity behind one is re-checked with the CMS on every request, so access revoked there takes effect within minutes, not at the end of the session.

4. Credentials

HeaderFor
Auth-Token: <CMS token> Recommended. Nothing is stored here; the CMS's 24 h expiry applies.
Authorization: Bearer <CMS token> The same token, for clients that dislike custom headers.
X-Service-Token: <token> Internal tooling. Named, and scoped to an explicit gateway list — no CMS user needed.

5. Who gets through

CMS super admins, callers with a facility-level role at the gateway's facility, and service tokens scoped to it. Tenancy-level callers — tenant, employee, WEG owner — are refused even though the CMS grants them access to that facility: master_rest is exempt from the gateway's own per-room permission checks, so a forwarded response covers the whole site, not one flat.

Use GET /me to see how your credentials are read, and GET /me/gateways for the gateways you can expect to reach (a hint list — the real decision is made per request against the CMS).

6. Endpoints

Endpoint
GET /gw/{gateway}/{path}the proxy itself
GET /meyour identity as the proxy resolves it
GET /me/gatewaysgateways you can expect to reach
GET /health liveness, credential-store state, effective policy, stale credentials
POST /auth/logincredentials → session token
POST /auth/logoutinvalidate a session token
GET /metrics counters (super admins and service tokens only)

7. Errors

Every error has the same shape — {"error": code, "detail": sentence} — so a client can branch on one field no matter which layer refused.

StatuserrorMeaning
401unauthenticated no credentials, or the CMS rejected them
403no_cms_access, tenancy_level_role, no_facility_role, service_token_scope the proxy's decision: you may not
403/400path_not_allowed outside the allowlist, or a smuggled path separator
404unknown_gateway no such gateway, or no credentials held for it — deliberately indistinguishable
405method not proxied
502gateway_unreachable, gateway_timeout, gateway_auth_failed, response_too_large the gateway failed, not you. gateway_auth_failed means the proxy's stored master_rest password is stale
502cms_unavailable no access decision could be made — never reported as a denial
429rate_limited, too_many_in_flight slow down — both carry Retry-After
503gateway_busy, credentials_unavailable too many in-flight requests for that gateway / no credential store

8. Limits and logging