skip to Main Content

hi I have a code of a telegram bot I am trying to connect it to a Excel file. The code is of Bot taking input and updating it to the excel worksheetk the error is // 2024-07-14 11:27:16,343 – main – ERROR – Error fetching Excel data: 400 Client Error: Bad Request for url: https://graph.microsoft.com/v1.0/me/drive/items/61814971F1322FC0!xxxx/earnify.xlsx/worksheets/Sheet1/range(address=’A1:F1000′)
2024-07-14 11:27:16,344 – main – ERROR – Failed to fetch Excel data. Unable to verify username. //

the ms graph output is

{"error":{"code":"InvalidAuthenticationToken","message":"Access token is empty.","innerError":{"date":"2024-07-14T11:56:25","request-id":"2cd7d68d-dbd0-49f0-909b-2bd0eb54xxxx","client-request-id":"2cd7d68d-dbd0-49f0-909b-2bd0eb54xxxx"}}}

and the Code is

# Function to get access token
def get_access_token():
    authority = f"https://login.microsoftonline.com/ed586964-ec89-4ecb-95bf-df20fb9axxxx"
    app = msal.ConfidentialClientApplication(CLIENT_ID, authority=authority, client_credential=CLIENT_SECRET)
    result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])

    if "access_token" in result:
        return result['access_token']
    else:
        logger.error(f"Failed to retrieve access token: {result.get('error')}")
        raise Exception("Could not retrieve access token")
# Function to read Excel file from OneDrive
def read_excel():
    access_token = get_access_token()
    if not access_token:
        logger.error("Failed to obtain access token. Unable to read Excel.")
        return None
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Accept': 'application/json',
    }
    url = f'https://graph.microsoft.com/v1.0/me/drive/items/61814971F1322FC0!xxxx/earnify.xlsx/worksheets/Sheet1/range(address='A1:F1000')'
    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        logger.error(f"Error fetching Excel data: {e}")
        return None

# Function to update Excel file in OneDrive
def update_excel(range_address, values):
    access_token = get_access_token()
    if not access_token:
        logger.error("Failed to obtain access token. Unable to update Excel.")
        return False
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json',
    }
    url = f'https://graph.microsoft.com/v1.0/me/drive/items/61814971F1322FC0!xxxx/workbook/worksheets/Sheet1/range(address='A1:F1000')'
    try:
        data = {
            "values": values
        }
        response = requests.patch(url, headers=headers, json=data)
        response.raise_for_status()
        return True
    except requests.exceptions.RequestException as e:
        logger.error(f"Error updating Excel data: {e}")
        return False

I first thought the Client Value is the Client secret as it had two ids one client value and client secret id in certificates and secrets in azure portal. so i changed it with client value but it didn’t worked so i rechanged the values but no luck. I am stuck i also thought of using google spreadsheet but the process to integrate it is too lengthy.

Someone help me out on this…

P.s : I changed python library to 2.7 or something casue one attribute was renamed in the latest version and it was causing an issue so maybe i think that is the problem or something else check it out is the values correct

2

Answers


  1. I see more issues.

    You are authenticating with client secret without singed-in user, but you are calling /me endpoint. /me endpoint can be called only when you are signed-in on behalf of a user.

    With client secret and application permissions, you can’t access workbook API. Workbook API doesn’t support application permissions.

    In read_excel function, there is wrong endpoint

    url = f'https://graph.microsoft.com/v1.0/me/drive/items/61814971F1322FC0!xxxx/earnify.xlsx/worksheets/Sheet1/range(address='A1:F1000')'
    

    You probably forgot to replace earnify.xlsx by workbook

    url = f'https://graph.microsoft.com/v1.0/me/drive/items/61814971F1322FC0!xxxx/workbook/worksheets/Sheet1/range(address='A1:F1000')'
    

    Try to change authentication and authenticate with a user. Also check that you granted delegated permission Files.ReadWrite to your Entra application.

    https://learn.microsoft.com/en-us/entra/msal/python/#basic-usage

    Login or Signup to reply.
  2. I agree with @user2250152, your code is using client credentials flow that works with permission of Application type. As mentioned in this MS Document, Application type permissions are not supported for updating worksheet

    To call /me endpoints, you need to switch to delegated flows like interactive flow or authorization code flow for generating token.

    Initially, I registered one Entra ID application and granted Files.ReadWrite permission of Delegated type as below:

    enter image description here

    In my case, I used interactive flow for which redirect URI should be http://localhost added in Mobile & desktop applications platform along with enabling public client flow option:

    enter image description here

    I have one Excel file with below sample data in my OneDrive account:

    enter image description here

    Now, I ran below modified python code that asks user to sign with interactive flow and updates excel successfully with below response:

    import logging
    import msal
    import requests
    import json
    
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger("main")
    
    CLIENT_ID = "appId"
    TENANT_ID = "tenantId"
    SCOPES = ["https://graph.microsoft.com/.default"]
    
    def get_access_token():
        authority = f"https://login.microsoftonline.com/{TENANT_ID}"
        app = msal.PublicClientApplication(CLIENT_ID, authority=authority)
    
        result = app.acquire_token_interactive(scopes=SCOPES)
    
        if "access_token" in result:
            return result['access_token']
        else:
            logger.error(f"Failed to retrieve access token: {result.get('error_description', result.get('error'))}")
            raise Exception("Could not retrieve access token")
    
    def read_excel():
        access_token = get_access_token()
        if not access_token:
            logger.error("Failed to obtain access token. Unable to read Excel.")
            return None
        headers = {
            'Authorization': f'Bearer {access_token}',
            'Accept': 'application/json',
        }
        url = "https://graph.microsoft.com/v1.0/me/drive/items/itemId/workbook/worksheets/Sheet1/range(address='A1:N6')"
        try:
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            logger.error(f"Error fetching Excel data: {e}")
            return None
    
    def update_excel(range_address, values):
        access_token = get_access_token()
        if not access_token:
            logger.error("Failed to obtain access token. Unable to update Excel.")
            return False
        headers = {
            'Authorization': f'Bearer {access_token}',
            'Content-Type': 'application/json',
        }
        url = f"https://graph.microsoft.com/v1.0/me/drive/items/itemId/workbook/worksheets/Sheet1/range(address='{range_address}')"
        try:
            data = {
                "values": values
            }
            response = requests.patch(url, headers=headers, json=data)
            response.raise_for_status()
            return True
        except requests.exceptions.RequestException as e:
            logger.error(f"Error updating Excel data: {e}")
            return False
    
    
    if __name__ == "__main__":
        range_address = "A1:N6"
        values = [
        ["Name", "Group Name", "Display name in reports", "Date of Joining", "Employee Number", "Designation", "Function", "Location", "Gender", "Date of Birth", "Father's/Mother's Name", "Address", "Phone No.", "E-mail"],
        ["John Doe", "Employee", "John", "01-Jan-21", 201, "Manager", "HR", "New York", "Male", "01-Jan-90", "Jane Doe", "123, Main Street, New York", 1234567890, "[email protected]"], ........
       ]
    
        excel_data = read_excel()
        if excel_data:
            logger.info(f"Current Excel data: {json.dumps(excel_data, indent=4)}")
    
        if update_excel(range_address, values):
            logger.info("Excel data updated successfully.")
        else:
            logger.error("Failed to update Excel data.")
    

    Response:

    enter image description here

    To confirm that, I checked the same in OneDrive where Excel data updated successfully like this:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search