Office365-REST-Python-Client icon indicating copy to clipboard operation
Office365-REST-Python-Client copied to clipboard

'401 Client Error: Unauthorized for url: https://tenant.sharepoint.com/sites/site/_api/contextInfo' when uploading a file to SharePoint with cert auth

Open nicklockhart-fullfibre opened this issue 3 months ago • 7 comments

Hi all,

Not sure if this is an issue with my environment/setup or a bug with the library. I'm currently trying to migrate a script using SAML auth (see #981) to certificate-based app-only auth. I have a cert which was generated as per the Microsoft documentation, which results in a PFX-format private key. I can see that this library needs a PEM-format private key.

I converted the PFX-format key to PEM-format using openssl:

openssl pkcs12 -in myapp.pfx -out myapp.pem -nodes

If I then check the fingerprint of the PEM-format key, it matches the PFK-format key:

openssl x509 -fingerprint -noout -in myapp.pem
SHA1 Fingerprint=8F:42:8E:60[...]

Screenshot of Windows Certmgr showing the same fingerprint

However, if I then try to upload a file to Sharepoint using certificate authentication...

    login_cert = {
        'tenant': 'tenant.onmicrosoft.com',
        'client_id': 'bc4b906b[...]',
        'thumbprint': '8f428e60[...]',
        'cert_path': '/usr/local/apps/move_to_sharepoint/myapp.pem',
    }
    ctx = ClientContext(site_url).with_client_certificate(**login_cert)

    # Specify destination folder
    folder = ctx.web.get_folder_by_server_relative_url("[path]")

    # Upload file
    local_file_path = args.filename
    with open(local_file_path, "rb") as f:
        file = folder.files.upload(f).execute_query()

...the following error is thrown:

Traceback (most recent call last):
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/runtime/client_request.py", line 37, in execute_query
    response = self.execute_request_direct(request)
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/runtime/client_request.py", line 46, in execute_request_direct
    self.beforeExecute.notify(request)
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/runtime/types/event_handler.py", line 41, in notify
    listener(*args, **kwargs)
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/sharepoint/client_context.py", line 278, in _build_modification_query
    self._ensure_form_digest(request)
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/sharepoint/client_context.py", line 216, in _ensure_form_digest
    self._ctx_web_info = self._get_context_web_information()
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/sharepoint/client_context.py", line 228, in _get_context_web_information
    response = client.execute_request_direct(request)
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/runtime/client_request.py", line 101, in execute_request_direct
    response.raise_for_status()
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/requests/models.py", line 1024, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://tenant.sharepoint.com/sites/site/_api/contextInfo

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/apps/move_to_sharepoint/move_to_sharepoint.py", line 37, in <module>
    file = folder.files.upload(f).execute_query()
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/runtime/client_object.py", line 55, in execute_query
    self.context.execute_query()
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/runtime/client_runtime_context.py", line 173, in execute_query
    self.pending_request().execute_query(qry)
  File "/usr/local/apps/move_to_sharepoint/venv/lib/python3.10/site-packages/office365/runtime/client_request.py", line 41, in execute_query
    raise ClientRequestException(*e.args, response=e.response)
office365.runtime.client_request_exception.ClientRequestException: (None, None, '401 Client Error: Unauthorized for url: https://tenant.sharepoint.com/sites/site/_api/contextInfo')

The app has been granted Sites.FullControl.All as per the library's documentation, so I don't think this is a permissions issue. The file upload code should be correct and previously worked OK when using username/password auth (sadly now deprecated).

Is this an issue with my environment (eg PKCS key converted to X509 via OpenSSL), a bug in my code (eg wrong params passed to with_client_certificate) or have I hit a bug in the library?

I'm using the latest version of the library (2.6.2) with Python 3.10.12 on Ubuntu 22.04 LTS, if that affects anything.

nicklockhart-fullfibre avatar Aug 29 '25 14:08 nicklockhart-fullfibre