Setting space properties via onConfluenceSpace() does not work out of the box

This is not a bug report as such because I think this is already being worked on, but more of an info dump if anyone else is running into this.

Problem

When using the properties API from @fore/api to write properties it will silently fail to do so if the property is being set on a Confluence space (and probably the same for Jira projects).
Example code:

import { properties } from '@forge/api';
// ...
properties.onConfluenceSpace('TEST').set('foo', 'bar')
   .then(() => properties.onConfluenceSpace('TEST').get('foo'))
   .then((value) => console.log(value)); // will output undefined

Debugging into the implementation of the properties API shows that it it internally just maps to the REST API for setting space properties which returns a 401 (unauthorised) response and just silently swallows that response. The 401 is likely a result of this permission bug in Forge: https://ecosystem.atlassian.net/browse/FRGE-212

Workaround
If you can’t use one of the other storage mechanism user you will need to manually assign the correct space permissions to the app user. In my case I assigned my app user as the space admin.

1 Like

Hi @thomas2 ,

Thanks for the great writeup. I would consider the swallowing of the 401 error to be a bug in Forge. I’ve left a comment to this effect in FRGE-212.

Regards,
Dugald

1 Like

Hello, I’m facing this issue too. I have added all the confluence permission scopes I could find to my forge manifest, including:

    - write:confluence-props
    - write:confluence-content
    - write:confluence-space
    - write:confluence-file
    - manage:confluence-configuration

None of these made the trick.

Since our intention is to port our current connect apps to forge, using the useSpaceProperty() hook is not a valid option, as those come prefixed.

As of now, using the Product Fetch API with user impersonation is the only way I found to write to space properties:

export const setSpaceProperty = async (spaceKey, key, value) => {
  const spaceApi = properties.onConfluenceSpace(spaceKey);
  // await spaceApi.set(key, value);
  // TODO: Replace this user impersonation workaround when the spaceApi works as it should
  const { version } = await api.asUser().requestConfluence(`/rest/api/space/${spaceKey}/property/${key}`, { method: 'GET' });
  await api.asUser().requestConfluence(`/rest/api/space/${spaceKey}/property/${key}`, {
    method: 'PUT',
    body: JSON.stringify({
      value,
      version: {
        number: version.number + 1,
        minorEdit: false
      }
    })
  });
  return spaceApi.get(key);
};

Hope this approach helps anyone in the same situation.

1 Like