td-ameritrade-python-api: Token Expired Error

I’m seeing an unexpected error and I was hoping there is some insight into the root cause. The client seems to be unable to refresh the access token ONLY after the client has been running for 30 minutes. Running grab_access_token() in the debugger prior to the token expiring does not throw any errors. But after the client has been connected for 30 minutes and then tries to request a new token, we get Unauthorized Error. Here is the code to reproduce.

    import time
    
    from td.client import TDClient
    
    TDSession = TDClient(
        client_id=CLIENT_ID,
        redirect_uri='http://localhost/authorizationcallback',
        credentials_path='C:/FULL/PATH/TO/JSON/FILE'
    )
    
    TDSession.login()
    
    while True:
        msft_quotes = TDSession.get_quotes(instruments=['MSFT'])
        print(msft_quotes)
    
        time.sleep(600)

Results in this stdout:

{‘MSFT’: {‘assetType’: ‘EQUITY’,}} {‘MSFT’: {‘assetType’: ‘EQUITY’}} {‘MSFT’: {‘assetType’: ‘EQUITY’}} Grabbing new access token… Traceback (most recent call last): File “scratch.py”, line 15, in <module> msft_quotes = TDSession.get_quotes(instruments=[‘MSFT’]) File “site-packages\td\client.py”, line 747, in get_quotes return self._make_request(method=‘get’, endpoint=endpoint, params=params) File “site-packages\td\client.py”, line 619, in _make_request raise TknExpError(message=response.text) td.exceptions.TknExpError: {“error”:“Not Authorized.”}

Reading through the code, i don’t see any reason why the server would reject the request at this point. Any help is great, thanks. As an alternative is there any downside to calling login() periodically?

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I just wanted to update everyone that I added a minor fix to the _make_request method. Now if the status code is 401 it will first try to grab a new access token and if that fails it will then raise the token expire error as more than likely the user’s Refresh token is expired and they need to go through the full authentication process again.

If you are running your program in an event loop, you can apparently keep it current by calling client.grab_access_token() periodically before it expires. Something like this:

async def update_token(TDSession):

    refresh_time = datetime.datetime.now() + datetime.timedelta(minutes=25)
    while True:
        if datetime.datetime.now() > refresh_time:
            client.grab_access_token()
            refresh_time = datetime.datetime.now() + datetime.timedelta(minutes=25)
        else:
            await asyncio.sleep(60)

async def main(TDSession):
    asyncio.create_task(update_token(TDSession))
    await asyncio.sleep(.1)
   # rest of trading logic

If you aren’t using coroutines, you may be able to run the update_token() in another thread, but I haven’t tried it yet. Still not sure why the error occurs after the token is expired.