schwab-py icon indicating copy to clipboard operation
schwab-py copied to clipboard

Access token not refreshing

Open bman393 opened this issue 1 year ago • 3 comments

Description of Bug I created my token with client_from_manual_flow, all my inputs are correct. It then only gives me a expires_in token of 1800 (30 min). Then I use schwab.auth.client_from_token_file to create my client which is also suppose to refresh my token as well right? But my token still expires on the first set 30 min My token file exists on the same level as the code I am using to grab quotes. Here is my code: `from schwab.auth import client_from_manual_flow api_key='', app_secret='', callback_url='https://127.0.0.1/', token_path='/mnt/c/Users/Brogan/Documents/tickerStats/schwab-py/token.json' def getPrice(ticker): client = schwab.auth.client_from_token_file(token_path, api_key, app_secret)

r = client.get_quote(ticker)

r=r.json() print(r) getPrice('$SPX')` Expected Behavior I expect the access token to update to a new expire time. Actual Behavior Instead, the token still expires at my original set time from the manual token creation. I have to manually create the token every 30 min to access schwab Error/Exception Log, If Applicable

bman393 avatar May 22 '24 17:05 bman393

Passing client fetch log: schwab-api version 0.0.0a29 Loading token from file /mnt/c/Users/Brogan/Documents/tickerStats/schwab-py/token.json Req 1: GET to https://api.schwabapi.com/marketdata/v1/$SPX/quotes, params={} Req 1: GET response: 200, content={"$SPX":{"assetMainType":"INDEX","realtime":true,"ssid":1819771877,"symbol":"$SPX","fundamental":{"avg10DaysVolume":0.0,"avg1YearVolume":0.0,"divAmount":0.0,"divFreq":0,"divPayAmount":0.0,"divYield":0.0,"eps":0.0,"fundLeverageFactor":0.0,"peRatio":0.0},"quote":{"52WeekHigh":5325.49,"52WeekLow":4103.78,"closePrice":5308.13,"highPrice":5324.32,"lastPrice":5321.41,"lowPrice":5297.87,"netChange":13.28,"netPercentChange":0.25018227,"openPrice":5298.69,"securityStatus":"Closed","totalVolume":1974738504,"tradeTime":1716325754901},"reference":{"description":"S\u0026P 500 INDEX","exchange":"0","exchangeName":"Index"}}} {'$SPX': {'assetMainType': 'INDEX', 'realtime': True, 'ssid': 1819771877, 'symbol': '$SPX', 'fundamental': {'avg10DaysVolume': 0.0, 'avg1YearVolume': 0.0, 'divAmount': 0.0, 'divFreq': 0, 'divPayAmount': 0.0, 'divYield': 0.0, 'eps': 0.0, 'fundLeverageFactor': 0.0, 'peRatio': 0.0}, 'quote': {'52WeekHigh': 5325.49, '52WeekLow': 4103.78, 'closePrice': 5308.13, 'highPrice': 5324.32, 'lastPrice': 5321.41, 'lowPrice': 5297.87, 'netChange': 13.28, 'netPercentChange': 0.25018227, 'openPrice': 5298.69, 'securityStatus': 'Closed', 'totalVolume': 1974738504, 'tradeTime': 1716325754901}, 'reference': {'description': 'S&P 500 INDEX', 'exchange': '0', 'exchangeName': 'Index'}}} BEGIN REDACTED LOGS [debug.py:151:_enable_bug_report_logging] schwab-api version 0.0.0a29 [auth.py:36:load_token] Loading token from file /mnt/c/Users/Brogan/Documents/tickerStats/schwab-py/token.json [synchronous.py:17:_get_request] Req 1: GET to https://api.schwabapi.com/marketdata/v1/$SPX/quotes, params={} [base.py:64:_log_response] Req 1: GET response: 200, content={"$SPX":{"assetMainType":"INDEX","realtime":true,"ssid":1819771877,"symbol":"$SPX","fundamental":{"avg10DaysVolume":0.0,"avg1YearVolume":0.0,"divAmount":0.0,"divFreq":0,"divPayAmount":0.0,"divYield":0.0,"eps":0.0,"fundLeverageFactor":0.0,"peRatio":0.0},"quote":{"52WeekHigh":5325.49,"52WeekLow":4103.78,"closePrice":5308.13,"highPrice":5324.32,"lastPrice":5321.41,"lowPrice":5297.87,"netChange":13.28,"netPercentChange":0.25018227,"openPrice":5298.69,"securityStatus":"Closed","totalVolume":1974738504,"tradeTime":1716325754901},"reference":{"description":"S\u0026P 500 INDEX","exchange":"0","exchangeName":"Index"}}}

Failing client fetch log: schwab-api version 0.0.0a29 Loading token from file token.json Req 1: GET to https://api.schwabapi.com/marketdata/v1/$SPX/quotes, params={} Traceback (most recent call last): File "get_quote.py", line 27, in getPrice('$SPX') File "get_quote.py", line 23, in getPrice r = client.get_quote(ticker) File "/mnt/c/Users/Brogan/Documents/tickerStats/schwab-py/schwab/client/base.py", line 456, in get_quote return self._get_request(path, params) File "/mnt/c/Users/Brogan/Documents/tickerStats/schwab-py/schwab/client/synchronous.py", line 19, in _get_request resp = self.session.get(dest, params=params) File "/home/brmcgraw/.local/lib/python3.6/site-packages/httpx/_client.py", line 983, in get timeout=timeout, File "/home/brmcgraw/.local/lib/python3.6/site-packages/authlib/integrations/httpx_client/oauth2_client.py", line 196, in request self.ensure_active_token() File "/home/brmcgraw/.local/lib/python3.6/site-packages/authlib/integrations/httpx_client/oauth2_client.py", line 207, in ensure_active_token self.refresh_token(url, refresh_token=refresh_token) File "/home/brmcgraw/.local/lib/python3.6/site-packages/authlib/oauth2/client.py", line 264, in refresh_token auth=auth, **session_kwargs) File "/home/brmcgraw/.local/lib/python3.6/site-packages/authlib/oauth2/client.py", line 275, in _refresh_token token = self.parse_response_token(resp.json()) File "/home/brmcgraw/.local/lib/python3.6/site-packages/authlib/oauth2/client.py", line 380, in parse_response_token self.handle_error(error, description) File "/home/brmcgraw/.local/lib/python3.6/site-packages/authlib/integrations/httpx_client/oauth2_client.py", line 188, in handle_error raise OAuthError(error_type, error_description) authlib.integrations.base_client.errors.OAuthError: invalid_client: Unauthorized BEGIN REDACTED LOGS [debug.py:151:_enable_bug_report_logging] schwab-api version 0.0.0a29 [auth.py:36:load_token] Loading token from file token.json [synchronous.py:17:_get_request] Req 1: GET to https://api.schwabapi.com/marketdata/v1/$SPX/quotes, params={}

bman393 avatar May 22 '24 17:05 bman393

I want to note that my callback url does not have the / at the end. When posting in here it automatically adds it. My callback in my code and app are an exact copy of eachother

bman393 avatar May 23 '24 15:05 bman393

I did just notice when I do the client_from_manual_flow, my callback url has the backslash, not sure if this is right: https://127.0.0.1/?code=C0.........

bman393 avatar May 23 '24 18:05 bman393

I want to note that my callback url does not have the / at the end. When posting in here it automatically adds it. My callback in my code and app are an exact copy of eachother

This looks like a quirk of the way github displays URLs. Next time, please wrap your code in triple backticks to format it properly.

alexgolec avatar May 25 '24 01:05 alexgolec

Adding some more context. I re-ran everything with python3.11 including the manual token creator. I get this error after 30 min:

Req 1: GET to https://api.schwabapi.com/marketdata/v1/SPY/quotes, params={}
Traceback (most recent call last):
  File "/mnt/c/Users/Brogan/Documents/tickerStats/temp/get_quote.py", line 32, in <module>
    getPrice('SPY')
  File "/mnt/c/Users/Brogan/Documents/tickerStats/temp/get_quote.py", line 28, in getPrice
    r = client.get_quote(ticker)
        ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Brogan/Documents/tickerStats/Temp/schwab-py/schwab/client/base.py", line 469, in get_quote
    return self._get_request(path, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Brogan/Documents/tickerStats/Temp/schwab-py/schwab/client/synchronous.py", line 19, in _get_request
    resp = self.session.get(dest, params=params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/httpx/_client.py", line 1054, in get
    return self.request(
           ^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/integrations/httpx_client/oauth2_client.py", line 201, in request
    if not self.ensure_active_token(self.token):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/oauth2/client.py", line 266, in ensure_active_token
    self.refresh_token(url, refresh_token=refresh_token)
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/oauth2/client.py", line 256, in refresh_token
    return self._refresh_token(
           ^^^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/oauth2/client.py", line 372, in _refresh_token
    resp = self._http_post(url, body=body, auth=auth, headers=headers, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/oauth2/client.py", line 426, in _http_post
    return self.session.post(
           ^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/httpx/_client.py", line 1145, in post
    return self.request(
           ^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/integrations/httpx_client/oauth2_client.py", line 206, in request
    return super().request(
           ^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/httpx/_client.py", line 827, in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/httpx/_client.py", line 914, in send
    response = self._send_handling_auth(
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/httpx/_client.py", line 939, in _send_handling_auth
    request = next(auth_flow)
              ^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/httpx/_auth.py", line 72, in sync_auth_flow
    request = next(flow)
              ^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/integrations/httpx_client/oauth2_client.py", line 43, in auth_flow
    url, headers, body = self.prepare(
                         ^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/oauth2/auth.py", line 67, in prepare
    return self.auth_method(self, method, uri, headers, body)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/brmcgraw/.local/lib/python3.11/site-packages/authlib/oauth2/auth.py", line 10, in encode_client_secret_basic
    text = f'{quote(client.client_id)}:{quote(client.client_secret)}'
              ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/urllib/parse.py", line 868, in quote
    return quote_from_bytes(string, safe)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/urllib/parse.py", line 898, in quote_from_bytes
    raise TypeError("quote_from_bytes() expected bytes")
TypeError: quote_from_bytes() expected bytes

 ### BEGIN REDACTED LOGS ###

[debug.py:151:_enable_bug_report_logging] schwab-api version 1.0.0
[synchronous.py:16:_get_request] Req 1: GET to https://api.schwabapi.com/marketdata/v1/SPY/quotes, params={}```

bman393 avatar May 29 '24 01:05 bman393

Are you consistently seeing this error?

alexgolec avatar May 29 '24 12:05 alexgolec

I haven't received any new instances of this issue since this change was released, so I'm marking this issue as closed. If anyone receives a 401 error, please reopen this issue and add your experience.

alexgolec avatar Jun 13 '24 02:06 alexgolec