alexgolec / tda-api

A TD Ameritrade API client for Python. Includes historical data for equities and ETFs, options chains, streaming order book data, complex order construction, and more.
https://tda-api.readthedocs.io
MIT License
1.26k stars 335 forks source link

auth.py:ensure_refresh_token_update function never updates refresh_token #341

Open jporacledba opened 9 months ago

jporacledba commented 9 months ago

Please read the bug submission guidelines before submitting a bug.

Not following guidelines may result in your bug being ignored and/or closed.

Description of Bug To be clear, I'm filing this bug to document this issue. It is a fringe issue that isn't likely worth fixing, but the code isn't working, so I wanted to report it in case it helps someone in the future. The ensure_refresh_token_update function in the auth.py module doesn't update the refresh token as described in its comments. The update_interval_seconds parameter isn't set any where in the client code I can find, so it's value is always None. It probably is supposed to be set to the expires_in field of the token JSON, but I'm not sure. Additionally, the code is examining the creation_timestamp which is related to the access_token not the refresh token, so I'm not sure what's going on. Practically speaking, some unknown function in the code triggers an update of the refresh_token if it's expired, and this works in a serial implementation, but if using the multiprocessing module, the expired token will be updated in the filesystem only and not in memory. So, every API call will generate a request to update the refresh_token and this will trigger the TD Ameritrade admin throttle limits for the token end point. This can be confusing because if the refresh_token on disk is valid at startup, the multiprocessing code will function normally until the refresh_token expires.

Code to Reproduce See the attached code file. Start with a token pair with a valid access_token and an expired refresh_token. Execute any API call. r = c.get_user_principals() Observe the log message:

[INFO:ensure_refresh_token_update:242]: Skipping refresh token update
[DEBUG:_get_request:15]: Req 1: GET to https://api.tdameritrade.com/v1/userprincipals, params={
    "apikey": "XXXX@AMER.OAUTHAP"
}
[DEBUG:_send_single_request:887]: HTTP Request: POST https://api.tdameritrade.com/v1/oauth2/token "HTTP/1.1 200 OK"
[INFO:update_token:29]: Updating token to file /tmp/token.json

Note, this message indicates the ensure_refresh_token_update is exiting. [INFO:ensure_refresh_token_update:242]: Skipping refresh token update

These messages follow indicating the token was actually updated by some intermediate functionality

[INFO:update_token:29]: Updating token to file /tmp/token.json

debug.py.out.txt debug.py.txt

IMPORTANT: Remember to anonymize your code. Be sure to replace API keys/Client IDs with placeholders. Also, never, ever share the contents of your token file.

Expected Behavior Update the session object in memory with the current refresh token.

Actual Behavior Rely on some unknown functionality to update the refresh_token. This doesn't work with the multiprocessing library.

Error/Exception Log, If Applicable See here to learn how to turn on debug logging: https://tda-api.readthedocs.io/en/latest/help.html