Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: 'str' object is not callable`ClientContext #877

Open
pdakwal opened this issue Jul 3, 2024 · 3 comments
Open

TypeError: 'str' object is not callable`ClientContext #877

pdakwal opened this issue Jul 3, 2024 · 3 comments
Labels

Comments

@pdakwal
Copy link

pdakwal commented Jul 3, 2024

Hi,

I am trying to access sharepoint sites using msal.

site_url = "https://organization.sharepoint.com/sites/mysite"
tenant_id = "xxxx-xxxx-xxxx"
client_id = "xxxx-xxxx-xxxx"
client_secret = "xxxx-xxxx-xxxx"
authority_url = f"https://login.microsoftonline.com/{tenant_id}"

app = msal.ConfidentialClientApplication(
    client_id,
    authority=authority_url,
    client_credential=client_secret
)

scope = ['https://graph.microsoft.com/.default']

result = app.acquire_token_for_client(scopes=scope)
print(result)

if "access_token" in result:
    print("Authentication successful")
    token = result['access_token']
    print(f"Token type: {type(token)}, Token: {token}")

    context = ClientContext(site_url).with_access_token(token)
    site = context.web
    context.load(site)
    context.execute_query()
  

I am getting the access token correctly but it throws following error while running the query on the context:

context.execute_query() File "/opt/conda/lib/python3.10/site-packages/office365/runtime/client_runtime_context.py", line 173, in execute_query self.pending_request().execute_query(qry) File "/opt/conda/lib/python3.10/site-packages/office365/runtime/client_request.py", line 37, in execute_query response = self.execute_request_direct(request) File "/opt/conda/lib/python3.10/site-packages/office365/runtime/client_request.py", line 46, in execute_request_direct self.beforeExecute.notify(request) File "/opt/conda/lib/python3.10/site-packages/office365/runtime/types/event_handler.py", line 41, in notify listener(*args, **kwargs) File "/opt/conda/lib/python3.10/site-packages/office365/sharepoint/client_context.py", line 283, in _authenticate_request self.authentication_context.authenticate_request(request) File "/opt/conda/lib/python3.10/site-packages/office365/runtime/auth/authentication_context.py", line 249, in authenticate_request self._authenticate(request) File "/opt/conda/lib/python3.10/site-packages/office365/runtime/auth/authentication_context.py", line 168, in _authenticate self._cached_token = token_func() TypeError: 'str' object is not callable

As far my understanding, all required permissions to the app are granted through AAD portal

Screenshot 2024-07-03 144505

Am I missing something? Or any other permissions should be added? Pleas help

@taatuut
Copy link

taatuut commented Aug 5, 2024

I'm hitting the same error. Using Office365-REST-Python-Client 2.5.11 (and msal 1.30.0).

@taatuut
Copy link

taatuut commented Aug 7, 2024

I could make it work in my particular Python script using SharePoint Online tenant_id and client_id combined with browser authentication by making the two changes below in .../site-packages/office365/runtime/auth/authentication_context.py
However, I have no idea if this would impact anything else.

def _get_authorization_header(token):
    # type: (Any) -> str
    return "{token_type} {access_token}".format(
        #ez20240808
        #token_type=token.tokenType, access_token=token.accessToken
        token_type="Bearer", access_token=token
    )
def _authenticate(request):
            if self._cached_token is None:
                #ez20240808
                #self._cached_token = token_func()
                self._cached_token = token_func
            request.set_header(
                "Authorization", _get_authorization_header(self._cached_token)
            )

@vgrem vgrem added the question label Sep 4, 2024
@Nyxius-AI
Copy link

The error occurs because with_access_token expects a function that returns the token, not the token string itself. This is necessary because with_access_token is designed to call the function dynamically to retrieve a fresh token when needed, which is important in OAuth2 flows where tokens can expire and need to be refreshed.

How to Fix the Issue
Instead of passing the token string directly, you should pass a function that returns the token. Here’s an example of how you can do this:

from dataclasses import dataclass

@dataclass
class Token:
    tokenType: str
    accessToken: str

# Function to retrieve the access token
def get_token():
    token_response = app.acquire_token_for_client(scopes=scopes)
    if "access_token" in token_response:
        return Token(tokenType="Bearer", accessToken=token_response["access_token"])
    else:
        raise Exception(
            f"Authentication error: {token_response.get('error')}, {token_response.get('error_description')}"
        )

# Use the get_token function in with_access_token
ctx = ClientContext(site_url).with_access_token(get_token)

Additionally, note that my Token class is mandatory because there is an error in the code that formats the token using the function:

def _get_authorization_header(token):
    # type: (Any) -> str
    return "{token_type} {access_token}".format(
        token_type=token.tokenType, access_token=token.accessToken
    )

This function expects a token as a dictionary but uses attribute accessors (.tokenType, .accessToken) instead of dict.get(). To resolve this, I introduced a Token class with attributes to handle the formatting correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants