WOPI integration
WOPI integration with Collabora
Build a signed document-editor app using platform-owned WOPI, explicit installation consent and the workspace SDK bridge.
Verentis Collaboration hosts WOPI on behalf of installed editor applications. Your app supplies an HTTPS editor wrapper and uses Collabora Online / CODE to display and edit documents. The platform owns document authorization, WOPI credentials, locks and persistence; you do not build another WOPI backend.
A WOPI-only app does not need a publisher OAuth client ID or client secret. It needs an actively signed package, approved installation consent and a trusted editor deployment. A signature establishes package provenance, not unrestricted runtime access to a workspace.
Supported integration
This guide covers Collabora and the existing-file launch flow. It does not promise
Microsoft 365 for the web compatibility, anonymous editing, arbitrary discovery
servers or the entire WOPI protocol surface. For this integration, declare
view and/or edit; a format must also be supported by the configured CODE
discovery document and the user's current permissions.
Who owns what
| Owner | Responsibilities |
|---|---|
| App publisher | Sign the package; declare wrapper/operator origins, formats and capabilities; implement the wrapper and SDK lifecycle. |
| Editor operator | Run CODE over trusted HTTPS, retain its RSA proof key, allow the platform WOPI origin, and protect document content and logs. The publisher may also be the operator. |
| Platform operator | Approve/configure trusted CODE discovery, operate Collaboration and provision its internal credentials, signing keys and private TLS. |
| Workspace installer | Review the exact signed candidate and consent to external document processing and requested operations. |
| Workspace user | Open documents using their current file permissions; installation consent does not grant the user new file access. |
A new CODE operator origin needs platform discovery configuration. An app manifest cannot make the platform fetch arbitrary URLs merely by declaring them. Multiple approved wrappers can use the same trusted CODE operator.
1. Declare the editor
The following application manifest illustrates a DOCX-only wrapper. Replace the publisher and origins with your own, then add the packaging configuration described in Publish an application.
api-version: verentis.io/v1
kind: Application
metadata:
name: document-editor
display-name: Document Editor
version: 0.1.0
author: Acme
spec:
entry: https://editor.example.com
scope: global
capabilities: [wopi]
permissions: []
mime-types:
- pattern: application/vnd.openxmlformats-officedocument.wordprocessingml.document
mode: edit
priority: 150
wopi:
editor-origin: https://editor.example.com
operator-origin: https://code.example.com
actions: [view, edit]
maximum-file-bytes: 52428800
idle-session-minutes: 30
files:
- mime-type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
extension: .docx
editable: true
sandbox:
allow-scripts: true
allow-same-origin: true
allow-forms: true
permissions: [] is intentional for this WOPI-only example. The host brokers
Collaboration operations using the user's authority; the editor does not need an
ordinary delegated file-write token. If your app also calls ordinary platform
APIs, declare and obtain their permissions independently.
The wrapper origin and CODE operator origin are different roles.
spec.entry must belong to wopi.editor-origin; operator-origin identifies CODE,
not the platform API. Neither field is the WOPI callback URL.
See the complete field reference.
2. Sign, publish and obtain consent
Use your publisher's active signing key and the normal signed publication workflow. Apply environment overrides before signing: changing origins or other declaration values afterward does not produce an authorized candidate.
Install the published package in a test workspace and review its WOPI consent. The review identifies the publisher, wrapper/operator origins, supported actions and files, limits and optional rename/delete operations. It also discloses that an external editor processes document content. Publication/moderation and workspace consent are separate decisions.
An unsigned package, a loose manifest without verified installation provenance, or a pending/revoked installation is not a WOPI launch authorization. See Installation & consent.
3. Receive the platform launch
Open a matching document from the workspace, rather than navigating directly to the wrapper. The host obtains a scoped embed ticket for the approved wrapper; the wrapper must validate framing through Collaboration. It then initializes the SDK and requests the document launch:
import { createVerentisClient } from '@verentis/sdk'
const client = createVerentisClient()
await client.whenReady()
if (client.context.surface !== 'file' ||
!client.context.installation?.wopiEnabled ||
!client.bridge) {
throw new Error('An approved workspace WOPI file launch is required.')
}
const launch = await client.bridge.requestWopiLaunch()
The launch contains the resolved editor action URL, editorOrigin, wopiSource,
scoped accessToken, epoch-millisecond accessTokenTtl, document identity and
read-only state. Use these values, not a token or document identifier supplied
by an arbitrary URL or another iframe. Treat the TTL as an absolute expiry, not
a duration to add to the current time.
Submit access_token and access_token_ttl as form fields to the validated
launch.action, targeting the CODE iframe. The resolved action already carries
the WOPISrc. Keep credentials out of browser storage, diagnostic output, analytics
and manually constructed navigation URLs. Validate both event.origin and
event.source for editor messages, and use an exact targetOrigin.
This snippet is not a complete framing implementation. The
Libre Office repository is the reference:
apps/editor contains the wrapper's embed/frame authorization and CODE integration;
manifests/office.app.yaml contains its signed declaration. The package name is
libre-office; internal source and workload names may still say office.
4. Save with durable acknowledgement
CODE performs file and lock callbacks against the platform's /wopi/files/...
endpoints. The wrapper coordinates the user interface through the SDK:
- Track a monotonically increasing local edit generation and mark the document dirty.
- Call
bridge.requestWopiSave(generation)to obtain a checkpoint and correlation. - Send CODE
Action_Savewith that correlation inValues.ExtendedData. - Poll
bridge.getWopiStatus()and correlate the platform receipt with the requested checkpoint and the editor's save response. - Clear dirty state only when the receipt identifies a durable revision for the requested save and no newer local edit invalidates that acknowledgement.
requestWopiSave does not upload the document. CODE's Action_Save_Resp alone,
or an unrelated revision change from another participant, is not proof that your
current edits were persisted. On timeout or unavailable status, preserve the
editor and show that changes remain unverified; do not report success or close it.
Save As uses WOPI PutRelativeFile. When status reports continuationAvailable,
call bridge.requestWopiContinuation() to rebind controls to the server-selected
target. The continuation contains target identity, not a new platform OAuth token
or permission to select an arbitrary document. Follow the reference wrapper's
transition handling; do not keep saving against the old source.
Call bridge.closeWopiSession() when explicitly closing a settled session. It
releases participation; it is not a substitute for saving.
5. Exercise the real integration
Use an isolated local platform and CODE deployment. Exercise signed installation, consent, open, edit, correlated save and fresh reopen. Also check read-only users, two participants, Save As, optional operations, expired credentials and installation revocation.
Package validation and mocked editor messages do not establish that CODE can reach the gateway, verify TLS, produce valid proof signatures or persist edits. Preserve unsaved content when authority expires or is revoked. Do not design a client around a promise that an in-flight write is cancelled at the exact instant an idle deadline passes.
Troubleshooting
| Symptom | Check |
|---|---|
| Wrapper refuses direct navigation | Launch through an installed app in the workspace; embed authorization is required. |
| No WOPI launch or consent denied | Exact signed candidate, active signer, installation approval and current document rights. |
| Unsupported file/action | Both MIME and extension declaration, editable, requested action and CODE discovery support. |
| Proof rejection or CODE cannot open | Trusted operator discovery, stable CODE proof key, clock, callback origin and TLS trust. Never disable proof checking. |
Redirect to *-api-service:8443 | Platform routing configuration: public HTTPS redirects belong at ingress, not the private API listeners. |
| Save response but no matching receipt | Correlation, newer local edits, live status and persistence outcome. Keep the editor open. |
WOPI credentials are valid only for WOPI. They cannot authenticate ordinary platform API calls. See Authentication for the separate OAuth and SDK-token paths.