ONLYOFFICE Docs CE — document security token (JWT) silently replaced with a fixed placeholder string in the co-authoring websocket "auth" message causing "document security token is not correctly formed"

We’re integrating self-hosted ONLYOFFICE Docs (Community Edition) into our own product via the standard DocsAPI.DocEditor() JS API, with JWT enabled on the Document Server. We’re hitting a reproducible bug where the editor’s own client code appears to replace a correctly-signed JWT with a fixed, unrelated placeholder string before sending it in the co-authoring websocket’s auth message — causing every session to fail with:

“The document security token is not correctly formed. Please contact your Document Server administrator.”

Environment

  • Self-hosted via Docker, tested on both onlyoffice/documentserver:10.0.0 and onlyoffice/documentserver:8.3.3 — identical failure on both, so this doesn’t appear to be version-specific.
  • JWT_ENABLED=true, a single shared secret used throughout (confirmed identical across services.CoAuthoring.secret.browser/inbox/outbox/session in local.json and the secret our backend signs with).
  • Editor is embedded cross-origin: our app (e.g. https://app.ourdomain.com) loads the Document Server’s api.js from a separate origin (https://docs.ourdomain.com) and calls DocsAPI.DocEditor(containerId, config) with a server-signed config.

What we verified before concluding this is client-side

  1. The config our backend sends over HTTP includes a correctly-signed JWT (config.token) — we independently decoded and verified it against the shared secret; it’s valid.
  2. We set a breakpoint in our own code at the exact line calling DocsAPI.DocEditor(containerId, config) and confirmed config.token still holds the correct, real JWT at that point.
  3. Despite that, the outgoing websocket message to /<version>/doc/<key>/c/ (Engine.IO packet type 40, Socket.IO auth) contains a token field with a fixed placeholder string — not our JWT, not empty/undefined, a different fixed value every time, with every other field in that same message (docid, documentCallbackUrl, user.id, etc.) correctly matching what we sent.
  4. We ruled out anything on our end: reproduces in a fresh Incognito profile (no extensions), with no DevTools local overrides, after unregistering the Document Server’s own service worker and clearing site data, with our own frontend’s third-party SDKs (Sentry, PostHog) disabled, and with editorConfig.coEditing set to {mode: "strict", change: false} (no change).
  5. Disabling services.CoAuthoring.token.enable.browser in local.json (i.e. turning off this specific JWT check) makes the document open and render correctly — so the rest of the flow (file fetch, conversion, rendering) works fine; the issue is isolated to this one check/connection.

Config shape used (values genericized, structure exact):

{
  "type": "embedded",
  "width": "100%",
  "height": "100%",
  "document": {
    "key": "doc-<uuid-hex>-base",
    "title": "example.xlsx",
    "url": "https://<presigned-s3-url>",
    "fileType": "xlsx"
  },
  "documentType": "cell",
  "editorConfig": {
    "mode": "view",
    "callbackUrl": "https://<our-callback-endpoint>",
    "user": { "id": "<uuid>", "name": "<name>" },
    "customization": { "forcesave": true }
  },
  "token": "<valid JWT signed with the shared secret, verified independently>"
}

Questions

  • Is this a known issue with the co-authoring/connection JWT check specifically (as opposed to the initial editor-config token, which validates fine)?
  • Is there an additional, undocumented config requirement for this specific websocket handshake that differs from the documented config.token contract?
  • Happy to provide a full HAR capture, the exact docservice log lines (checkJwtForConnection refused: ...), or a minimal standalone repro if useful.

Thanks for any guidance