Search code examples
python-3.xpython-requestsyahoo-api

Yahoo API - Unable to request new access token once previous access token has expired


I am attempting to use Yahoo's API for fantasy football. I am able to receive an access token and refresh token initially, but once that access token has expired, I am unable to get another one.

My code is as follows:

from requests import Request, get, post
import webbrowser
import base64

baseURL = 'https://api.login.yahoo.com/'
oauthENDPOINT = "https://api.login.yahoo.com/oauth2/request_auth"


## Generate a url using the endpoint and parameters above
params = {'client_id' : client_id,
          'redirect_uri' : "oob",
          'response_type' : 'code'}
p = Request('GET', oauthENDPOINT, params=params).prepare()

webbrowser.open(p.url)

The last line sends me to the Yahoo website where I allow myself access and receive authCode.

encoded = base64.b64encode((client_id + ':' + client_secret).encode("utf-8"))
headers = {
    'Authorization': f'Basic {encoded.decode("utf-8")}',
    'Content-Type': 'application/x-www-form-urlencoded'
}
data = {
    'grant_type': 'authorization_code',
    'redirect_uri': 'oob',
    'code': authCode}

tokenResponse = post(baseURL + 'oauth2/get_token', headers=headers, data=data)
tokenResponseJSON = tokenResponse.json()
access_token = tokenResponseJSON['access_token']
refresh_token = tokenResponseJSON['refresh_token']

I now have all the information necessary to examine the settings of my league (for example).

fbURL = 'https://fantasysports.yahooapis.com/fantasy/v2'

leagueURL1 = f'{fbURL}/leagues;league_keys=nfl.l.{leagueID}/settings'

headers = {
    'Authorization': f'Bearer {access_token}',
    'Accept': 'application/json',
    'Content-Type': 'application/json'
}

response2 = get(leagueURL1, headers=headers,params={'format': 'json'})

The above works as expected. However, the access_token lasts for 3600 seconds and once that time has expired I am unable to request a new one, using my refresh_token. My attempt:

accessTokenData = {
    'grant_type': 'refresh_token',
    'redirect_uri': 'oob',
    'code': authCode,
    'refresh_token': refresh_token
}

accessTokenResponse = post(baseURL + 'oauth2/get_token', headers=headers, data=accessTokenData)
accessTokenJSON = accessTokenResponse.json()

In the above, I am hoping to receive a new access_token, but instead accessTokenJSON is this:

{'error': {'localizedMessage': 'client request is not acceptable or not supported',
  'errorId': 'INVALID_INPUT',
  'message': 'client request is not acceptable or not supported'}}

Up to this point I have been following these steps, which worked well up to this point. What am I doing wrong? I understand many Python users use yahoo_oauth or rauth for authentication, but that involves saving the client_id and client_secret in a .json file separately and I'm looking to load those in dynamically. I don't think I'm very far away from succeeding, but I'm just missing something when it comes to generating a new refresh_token. All help much appreciated!


Solution

  • Thanks to referring back to our guide.

    Managed to reproduce your error and it's really simple to solve.

    You are redefining the headers variable in your request to the fantasyspot url.

    The headers variable should be the same in the call for requesting a new access_token using the refresh_token as it was when initially getting both tokens using the auth_code.

    So just define header before making requesting a new access_token. Should look like the the following:

    headers = {
        'Authorization': f'Basic {encoded.decode("utf-8")}',
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    response = post(base_url + 'oauth2/get_token', headers=headers, data=data)
    

    Should work now.

    Recommend using different variable names for the headers used for getting an access_token and the one used to the fantasy sport url.