O365 / python-o365

A simple python library to interact with Microsoft Graph and Office 365 API
Apache License 2.0
1.65k stars 419 forks source link

401 Access token is empty when it is not #1089

Closed Bakura01 closed 2 months ago

Bakura01 commented 3 months ago

My Problem: I have made a program, that gets the number of emails inside an inbox. It also saves and loads the tokens correctly from the token backend, but i get an error, that my request to see the mailbox has no access token.

Help needed: Did I miss a step with authentication or is it not loading my token and the request is send before the token loads? Authentication is True if I have a token stored inside my backend and I do get it when I use test prints. What is wrong?

Error:

Client Error: 401 Client Error: Unauthorized for url: https://graph.microsoft.com/v1.0/users/testemail@test.com/mailFolders/Inbox/messages?%24top=25 | Error Message: Access token is empty. | Error Code:

My email code:

def checkAuthentication(self):
    """ Checks if the User is already authenticated 
    """
    if(self.account.is_authenticated == True):
      print("Current Emails:", self.getInboxEmails())
    else:
      print("no authentication")
      self.manualAuthentication()

  def getInboxEmails(self):
    """Get the emails of the current User """
    try:
      mailbox = self.account.mailbox(resource=str(self.email))
      mailbox = mailbox.inbox_folder()
      for email in mailbox.get_messages():
        self.emailCount += 1
        print("New messages: ",str(self.emailCount)," at ",str(datetime.datetime.now()))
      return self.emailCount
    except:
      print("An error occurred while trying to fetch your mailbox or inbox")
      return 0 

My token backend code:

def load_token(self):
        token = None
        response =  requests.get(f"http://localhost:5001/getToken/{self.email}")
        response = response.json()
        response = f"{response}".replace("'",'"')
        print("the email",self.email)
        print("response: ",response)
        if response != "None" and response != "" and response != '' and response != None:
            token = self.token_constructor(self.serializer.loads(response))
            print(token)
            return token
        else:
            return None

    def save_token(self):
        headers = {"content-type": "application/json"}
        data={
            "authToken":str(self.token)
        }
        response =  requests.post(url=f"http://localhost:5001/saveToken/{self.email}",headers=headers,data=None,json=data)
        return True
Bakura01 commented 3 months ago

My temporary fix:

 # new try using a direct get request --> Does work but only with the access token 
      # todo refresh token somehow for every time the code runs 
      self.token = (self.account.connection.token_backend.load_token())["access_token"]
      directUrl = f"https://graph.microsoft.com/v1.0/users/{self.email}/mailFolders/Inbox/messages"
      headers = {
        "Authorization" : f"{self.token}",
        "ContentType": "application/json"
      }
      try:
        response = requests.get(url=directUrl,headers=headers)
        # todo check for what is gotten back by the api
        # email count is wrong because it reads all objects i only need names or something of that sort
        for email in response:
          print(email)
          self.emailCount += 1
        print("New messages: ",str(self.emailCount)," at ",str(datetime.datetime.now()))
        return self.emailCount
      except Exception:
        print(Exception)

That fixes the request, because i explicitly send only the access token my self not with this library but as such i cannot refresh my access token with it for some reason

Bakura01 commented 3 months ago

I just noticed that my the session object has no access token stored. I don't know what happened i do load the token and return it ? --> Fix: load the session when creating an account object

alejcas commented 3 months ago

I don't have enough data to answer you.

Is this program run on a server or just on your machine?

Bakura01 commented 3 months ago

Thank you for the answear!

The current version is running on my machine, but later on a server.

Actions the code program does:

When i try to print the full token it does return it correctly. Maybe i am storing the token falsely once i load it from my backend?

Bakura01 commented 2 months ago

I think I found my error, but i don't really know how to fix it I would guess when I try to get the emails I use the standard connection class that this library provides and not my token backend. --> Every time i try to get messages this request is done by the connection class which does the request with its session object.

When the _internal_request() is called the header is always just {}

Bakura01 commented 2 months ago

Fixed it by implementing the _internal_request function inside my own program