vgrem / Office365-REST-Python-Client

Microsoft 365 & Microsoft Graph Library for Python
MIT License
1.34k stars 335 forks source link

Unable to authenticate to the Sharepoint site #629

Open Rafalz13 opened 1 year ago

Rafalz13 commented 1 year ago

Hi, I have a problem with authentication to Sharepoint to download some files. I used this code for the test connection:

from office365.runtime.auth.authentication_context import AuthenticationContext
from office365.sharepoint.client_context import ClientContext

app_settings = {
 'url': "https://tenant.sharepoint.com/sites/page",
 'client_id': client_id,
 'client_secret': client_secret,
}

context_auth = AuthenticationContext(url=app_settings['url'])
context_auth.acquire_token_for_app(client_id=app_settings['client_id'], client_secret=app_settings['client_secret'])

ctx = ClientContext(app_settings['url'], context_auth)
web = ctx.web
ctx.load(web)
ctx.execute_query()
print("Web site title: {0}".format(web.properties['Title']))

I got this error:

ValueError: {"error":"unauthorized_client","error_description":"AADSTS700016: Application with identifier '('xxx-xxx-xxx-xxx-xxx',)' was not found in the directory '[NAME]'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.\r\nTrace ID: [ID]\r\nCorrelation ID: [ID]\r\nTimestamp: 2023-01-10 14:56:31Z","error_codes":[700016],"timestamp":"2023-01-10 14:56:31Z","trace_id":"[ID]","correlation_id":"[ID]","error_uri":"https://accounts.accesscontrol.windows.net/error?code=700016"}

I can see a tenant related error. Is there any way to get a token here or pass the tenant_id for this method? Or maybe the problem is somewhere else? Has anyone had a similar problem?

For the other method, the error is that the client is forbidden for the URL.

ctx = ClientContext(site_url).with_credentials(ClientCredential('client_id', 'client_secret'))

web = ctx.web
ctx.load(web)
ctx.execute_query()
print(f"Web title: {web.properties['Title']}")
ClientRequestException: (None, None, '403 Client Error: Forbidden for url: https://tenant.sharepoint.com/_api_Web

Could you help me with this? I was informed that on the Azure side, the client should have access to sharepoint destinations (unfortunately I don't have access to it)

stansy60 commented 1 year ago

Are you sure your url is correct? https://<tenant>.sharepoint.com/sites/<team site> It works fine in my program:

ctx = ClientContext(url).with_credentials(UserCredential(user, password))
web = ctx.web
ctx.load(web)
ctx.execute_query()
Rafalz13 commented 1 year ago

The URL is correct. Your code also works for me. I can connect and download files from Sharepoint. But it works with user+password, not client_id + client_secret. Here is the problem.

stansy60 commented 1 year ago

I can't help you, I have no experience with Azure.

Danxx26hub commented 1 year ago

Did you create your clientid / client secret in the SharePoint and then trust the app? Check out this tutorial: https://code2care.org/sharepoint/how-to-generate-client-id-and-secret-to-register-sharepoint-app-with-outh-rest

softbreakers commented 1 year ago

I found the same problem. Solved with certificate authentication. I don't know why, but client secret authentication grants access to other APIs like Microsoft Graph, but not with Sharepoint API.

Rafalz13 commented 1 year ago

@Danxx26hub Thanks. I gave this tutorial to the person who was responsible for setting it up. I'm waiting for the result. @softbreakers I also tried using certificate_auth :D Certificate_path/private_key is missing. I don't know where I can find them. I've got the client's details, the tenant's, and the thumbprint. I also need cert_path for this method.

Rafalz13 commented 1 year ago

Hi again. We were able to generate the access token. Do you know how to pass this token to be able to connect to SharePoint pages? Authentication context has a context_auth.with_access_token() method - but we need to provide a function there. Is there another way to pass the generated token?

suomiko1 commented 1 year ago

find a file called Lib\site-packages\office365\runtime\auth\providers\acs_token_provider.py

open it and edit a function called _get_realm_from_target_url like this

def _get_realm_from_target_url(self):
    response = requests.head(url=self.url+'/_vti_bin/client.svc/', headers={'Authorization': 'Bearer'})
    return self.process_realm_response(response)

just add +'/_vti_bin/client.svc/' after self.url

it seems auth protocol changed in office365 online

now retry to auth

from office365.sharepoint.client_context import ClientContext from office365.runtime.auth.client_credential import ClientCredential

test_client_credentials = ClientCredential('my_app_only_client_id', 'my_app_only_client_secret')

ctx = ClientContext(test_site_url).with_credentials(test_client_credentials) target_web = ctx.web.get().execute_query() print(target_web.url)

good luck :p

guidorietbroek commented 1 year ago

I'm getting a AADSTS900144 - The request body must contain the following parameter: 'client_secret' using the standard code. I followed the steps to create client id and secret, also trusted this app.

`site_url = "https://{}.sharepoint.com/sites/{}".format(MS_TENANT, MS_SITE)

client_credentials = ClientCredential(client_id=MS_CLIENT_ID, client_secret=MS_CLIENT_SECRET) ctx = ClientContext(site_url).with_credentials(client_credentials)

web = ctx.web ctx.load(web) ctx.execute_query() ` Anyone an idea what's going wrong?