Static macros & impersonating app user: “no valid active user exists”

My app has some dynamic macros that have a static render mode for export. To render the export view, my app needs to fetch some data from Confluence, and it does so by impersonating the current user using addon.httpClient(req).asUserByAccountId(req.context.userAccountId) from atlassian-connect-express.

When I export a page using the macro to PDF, or when I expand body.export_view in the REST API, or when I render the page using any app that fetches the export view from the frontend, my export view renders fine, as the static render mode is called in the context of the current user.

However, when I render the page using an app that fetches the export view from the backend using JWT authentication (authenticating as its own app user), my export view fails to render. The reason seems to be that my backend cannot impersonate the app user of the other app. Trying to use the Confluence API in such a way will result in a 403 error with the message: Add-on 'com.k15t.orderly.databases' disallowed to impersonate the user because 'no valid active user exists'.

In particular, I am trying to get my static macro to render when publishing a help center using Scroll Viewport. The Viewport team have told me that they are experiencing this issue with some macros, but not with others. For example draw.io macros seem to work fine. Are they maybe using their own app user to make requests against Confluence? I’m not sure that would be an option from a security and a UX perspective for me.

Is this something that can be fixed in Confluence? Are there any suggested workarounds?

4 Likes

As a manual workaround, I am now manually detecting the Scroll Viewport app user by its account ID and in that case run a modified flow: Requests against Confluence are made using my own app user, and when fetching a content object, a second request is made against the Confluence API to verify that the Scroll Viewport app user has permission to see that content, using the permissions API.

This workaround works, but it does not work well. First of all, users will not understand why in certain cases they have to give space and content access to both the Scroll Viewport app user and my app user to publish a Viewport, particularly because they never have to deal with my app user in any other place. Second of all, manually checking all content objects against the permissions API is unpractical in many cases, as only one content ID can be checked per request. Imagine doing a CQL request that returns 100 pages, and then having to make one permissions API request per page.

And of course this workaround only solves the problem for one app integration. In fact, Confluence itself seems to make a request against my macro backend every time a page containing my macro is saved, as app user 5b70c8b80fd0ac05d389f5e9 (Chat Notifications), which raises an error in my backend.