atlassian-api / atlassian-python-api

Atlassian Python REST API wrapper
https://atlassian-python-api.readthedocs.io
Apache License 2.0
1.36k stars 664 forks source link

[Confluence] 403 error when using create_page, page_exists in a space that I own #713

Open RamNewton opened 3 years ago

RamNewton commented 3 years ago

I'm a newbie, I might have missed something basic.

confluence = Confluence(
    url='https://hello.atlassian.net',
    username=config.USERNAME,
    password=config.API_TOKEN,
    cloud=True)

status = confluence.create_page(
    space='Ram Newton A',
    title='Created through API',
    body="If you are seeing this, I got the page creation script right.")

I am using my API token for authentication. I'm able to add pages to that space via GUI. Is there a way to check if I was authenticated successfully?

gonchik commented 3 years ago

Let me reproduce on my cloud instance

bubthegreat commented 3 years ago

I had a similar issue but it was fixed by providing the space KEY instead of the space name -

confluence.get_space("~770263778")
{'id': 794427436,
 'key': '~770263778',
 'name': 'Mike Taylor',
 'description': {'plain': {'value': '',
   'representation': 'plain',

When creating it with the space key instead of the space name it works:

confluence.create_page("~770263778", title="Test Title", body="This was generated via API.")
{'id': '1859944609',
 'type': 'page',
 'status': 'current',
 'title': 'Test Title',
 'space': {'id': 794427436,
  'key': '~770263778',
  'name': 'Mike Taylor',

The params just have :space: in them - it would be helpful to update the docstrings or the parameter name to reflect that.

dephekt commented 3 years ago

@bubthegreat is right that the value for space here is supposed to be an object representing the key of the space. That is clarified in the REST API documentation here. Scroll down to the space parameter and click on the link to object and you will see:

key Required

string

The key of the space.

So we need to update that docstring or change the name of the parameter (maybe both) to indicate it's really space_key.

A separate issue that I don't think is in play here, but I just found, is that we're handling an HTTPError exception and if the status_code was 404, we're then raising an ApiPermissionError that the calling user doesn't have permission to view the content. According to the documentation, a 401 will be returned if "the authentication credentials are incorrect or missing from the request" and a 403 will be returned if:

Maybe we shouldn't intercept that HTTPError at all and just let it raise? I'm not sure what utility anyone gains by handling that 404 in the way we are versus just removing that whole try/except block and try to return self.post(url, data=data) and if there's an HTTPError exception just let it bubble up and give the real reason why to the caller. Maybe I don't have some context around why that was implemented in this way to begin with.