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?

6 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.

I ran into the same issue. Whenever a page is saved that contains a dynamic macro I see two export view requests by confluence with the ‘Chat notifications’ user in the JWT. One for the page with content ID that’s been saved and one for its previous page revision.

My gut feeling is that those requests are used to create a diff view that’s displayed somewhere, maybe in a notification mail, since there is a request for the current and its predecessor revision. I don’t know, it doesn’t really matter.

I haven’t found a way to identify those requests generically, so they can’t easily be ignored so to not spam our logs with this Add-on '<add-on name>' disallowed to impersonate the user because 'no valid active user exists'.
Executing an additional permission check request for each incoming macro render export view request is not a good workaround since it’s so much cheaper to just let the request fail.
The same is true for additional requests to find out if the user is this ‘Chat Notifications’-user and then ignore it.