Skip to main content
Version: Latest

Confluence (user passthrough)

Proxy for the Atlassian Confluence Cloud REST API via the managed gateway.

What this connector does

Gives agents gated, per-user access to Confluence for:

  • Searching content with CQL.
  • Reading pages (with body), their children, labels, and attachments.
  • Listing spaces and the pages within them.
  • Reading and posting page (footer) comments.
  • Creating and updating pages.

All operations are gated by PBAC policy. Every call flows: agent → gateway → /introspect (with this connector's resource_type) → OPA decision → Confluence API → response.

This connector ships in idp_passthrough mode only: the gateway forwards each calling user's own Atlassian OAuth token (captured when they log in to PolicyArc through the Atlassian IdP), as Authorization: Bearer. Confluence enforces its own space and page permissions, and its audit shows the real person. There is no shared service-account mode — Atlassian Cloud exposes no service identity at the OAuth layer (see the Atlassian products page).

API surface

Content and spaces use the Confluence v2 API (/wiki/api/v2/*), Atlassian's current REST API. CQL search uses the v1 endpoint (/wiki/rest/api/search) because v2 has no CQL equivalent.

Because the v2 API is used, the connector requests granular Atlassian OAuth scopes (read:page:confluence, write:page:confluence, read:space:confluence, read:comment:confluence, write:comment:confluence, read:attachment:confluence, read:label:confluence, search:confluence, plus read:me and offline_access) — not the classic read:confluence-content.all family, which the v2 API rejects with HTTP 401 "scope does not match". Grant these granular scopes on the Atlassian 3LO app's Confluence API permission.

Two Confluence quirks the tools document inline:

  • Body representation. Page and comment bodies use the storage representation (Confluence XHTML), e.g. {"representation": "storage", "value": "<p>Hello</p>"} — not plain text.
  • Optimistic locking on update. update_page requires the next version number. Call get_page first, read version.number, then pass version: {"number": N+1}.

Prerequisites

  • A Confluence Cloud account with access to the spaces/pages you want to reach.
  • An Atlassian IdP registered in PolicyArc (provider key atlassian). Pick Atlassian in the IdP setup wizard — the bundled preset fills in the endpoints and the required audience=api.atlassian.com authorize param. You supply the Client ID / secret from an Atlassian OAuth 2.0 (3LO) app (developer.atlassian.com) whose callback URL is the AS's /oauth2/callback, with the Confluence API permission granted for the connector's granular scopes (see above).
  • Your site's cloud ID — get it from https://<site>.atlassian.net/_edge/tenant_info.

See Atlassian products — multi-connector setup for the full 3LO walkthrough (shared with the Jira connector).

Install

Provide two setup fields: Atlassian site (the subdomain, e.g. acme) and Atlassian cloud ID (the UUID). Passthrough installs need no secret. On install, the gateway merges this connector's upstream_scopes into the Atlassian IdP row, so users re-consent to the union on their next login.

Verify

Request a token with a Confluence scope and call through the gateway as a logged-in user (passthrough needs a user session, so client_credentials will return a 502 "no stored IdP token"):

curl "https://<your-as>/gateway/confluence/wiki/api/v2/spaces" \
-H "Authorization: Bearer <user-token>"

A 200 with the spaces JSON confirms: token → introspect allowed → gateway proxied → Confluence responded as the user.

What can go wrong

SymptomCauseFix
502 "no stored IdP token"Caller never logged in through the atlassian IdP (or used client_credentials, which has no user context)Re-authenticate via Atlassian.
403 from ConfluenceThe user lacks permission on the space/page, or the token is missing a scopeCheck the user's Confluence permissions and that the Atlassian app granted the scope.
400 on create/updateBody sent as plain text instead of the storage representationWrap content as {"representation": "storage", "value": "<p>...</p>"}.
409 on updateStale version.numberRe-read with get_page and pass version.number + 1.
403 from the gatewayAgent lacks the route's PBAC scopeRequest a token with the matching confluence:* scope.
Stored IdP token missing required scopesConnector installed after the user logged inUser signs out and back in to re-consent.

Reference

Manifest reference

  • ID: identos.confluence
  • Version: 1.0.0
  • Resource type: urn:connector:identos:confluence
  • Capabilities: mcp

Supported auth modes

TypeDetails
idp_passthroughrequires IdP atlassian; setup fields: site, cloudid

Setup fields

IDLabelDefaultSecret?Notes
siteAtlassian sitenoplaceholder: acme / The subdomain of your Atlassian cloud URL (e.g. 'acme' for acme.atlassian.net). Used in resource IDs and to locate the cloud ID.
cloudidAtlassian cloud IDnoplaceholder: 11223344-5566-7788-9900-aabbccddeeff / UUID identifying your Atlassian site. Get from https://{site}.atlassian.net/_edge/tenant_info (the cloudId field). Required because Atlassian Cloud OAuth tokens route through https://api.atlassian.com/ex/confluence/\{cloudid\}/, not the site URL directly.

Scopes

Scope
confluence:content:read
confluence:content:write
confluence:space:read
confluence:comments:read
confluence:comments:write

Routes

MethodPatternScopeResource template
GET/wiki/rest/api/searchconfluence:content:read
GET/wiki/api/v2/pages/{id}confluence:content:readconfluence://{{site}}/pages/{{id}}
GET/wiki/api/v2/pagesconfluence:content:read
GET/wiki/api/v2/pages/{id}/childrenconfluence:content:readconfluence://{{site}}/pages/{{id}}
GET/wiki/api/v2/pages/{id}/labelsconfluence:content:readconfluence://{{site}}/pages/{{id}}
GET/wiki/api/v2/pages/{id}/attachmentsconfluence:content:readconfluence://{{site}}/pages/{{id}}
GET/wiki/api/v2/spacesconfluence:space:read
GET/wiki/api/v2/spaces/{id}confluence:space:readconfluence://{{site}}/spaces/{{id}}
GET/wiki/api/v2/spaces/{id}/pagesconfluence:space:readconfluence://{{site}}/spaces/{{id}}
GET/wiki/api/v2/pages/{id}/footer-commentsconfluence:comments:readconfluence://{{site}}/pages/{{id}}
POST/wiki/api/v2/pagesconfluence:content:write
PUT/wiki/api/v2/pages/{id}confluence:content:writeconfluence://{{site}}/pages/{{id}}
POST/wiki/api/v2/footer-commentsconfluence:comments:write

MCP tools

NameScopeDescription
search_pagesconfluence:content:readSearch Confluence content with CQL (Confluence Query Language). Example cql: "type=page AND space=DEV AND text ~ "onboarding"". Returns {results, _links:{next}, ...}; pass the opaque cursor from _links.next (or start) to page. This is Confluence's v1 search endpoint — the v2 API has no CQL equivalent.
get_pageconfluence:content:readGet a single Confluence page by numeric id. By default the body is NOT included — pass body-format=storage (or atlas_doc_format) to get the content. The response carries version.number, which you MUST read and increment before calling update_page (optimistic locking).
list_pagesconfluence:content:readList pages, optionally filtered by space id, title, or status. Paginated via the opaque cursor from _links.next.
get_page_childrenconfluence:content:readList the direct child pages of a Confluence page (one level). Paginated via cursor.
list_page_labelsconfluence:content:readList the labels attached to a Confluence page.
list_page_attachmentsconfluence:content:readList attachments on a Confluence page (metadata only — title, mediaType, fileSize, downloadLink).
list_spacesconfluence:space:readList Confluence spaces the caller can see. Use the returned numeric space id for list_pages/list_space_pages and the key (e.g. DEV) in CQL. Paginated via cursor.
get_spaceconfluence:space:readGet a single Confluence space by its numeric id.
list_space_pagesconfluence:space:readList pages in a Confluence space. Paginated via cursor.
list_page_commentsconfluence:comments:readList footer comments on a Confluence page. (Footer comments are the page-level comment thread; inline comments are a separate endpoint not exposed here.)
create_pageconfluence:content:writeCreate a Confluence page. The body uses the storage representation (Confluence XHTML), NOT plain text. Minimal valid shape: {"spaceId": "123456", "status": "current", "title": "My page", "body": {"representation": "storage", "value": "<p>Hello</p>"}}. Get spaceId from list_spaces. To nest under a parent, add "parentId": "<pageId>".
update_pageconfluence:content:writeUpdate a Confluence page. OPTIMISTIC LOCKING: call get_page first, read version.number, and pass version:{number: N+1}. The body uses the storage representation (same caveat as create_page). Required fields: id, status, title, body, version. Example: {"id": "123", "status": "current", "title": "My page", "body": {"representation": "storage", "value": "<p>Updated</p>"}, "version": {"number": 4, "message": "edit via agent"}}.
add_commentconfluence:comments:writeAdd a footer comment to a Confluence page. Body uses the storage representation. Shape: {"pageId": "123", "body": {"representation": "storage", "value": "<p>Looks good.</p>"}}. To reply to an existing comment, add "parentCommentId".