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: [FRGE-212] - Ecosystem Jira

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