Search code examples
phpnode.jsoauth-2.0yahoo-api

Yahoo Fantasy Sports example using OAuth2


I'd like to build an application to query the data in my Yahoo! Fantasy league but can't make it past the 3-legged OAuth authentication and was hoping someone could give me a quick demo, or point me to a relevant tutorial.

I'm willing to use NodeJS, Python or PHP.

I've registered an API and gotten a Consumer Key and Consumer Secret.

Their documentation contains two PHP examples (that I couldn't get to work) and references OAuth.net's list of libaries.

But let's take Python. The rauth documentation only lists the first leg, how am I supposed to complete the other 2 legs?

from rauth import OAuth2Service

yahoo = OAuth2Service(  
client_id='mykey',
client_secret='mysecret',
name='yahoo',
authorize_url='https://api.login.yahoo.com/oauth/v2/request_auth',
access_token_url='https://api.login.yahoo.com/oauth/v2/get_token',
base_url='https://api.login.yahoo.com/oauth/v2/')

url = yahoo.get_authorize_url()

Almost all of the examples I found on GitHub.com are years old and have compatibility problems, although yahoofantasysandbox seemed almost there.

This tutorial recommens using fantasy-sports but I didn't see a lot of details on implementation or examples.

Can someone either point me in the right direction on this or give me a demo of working code?


Solution

  • One year later I've managed to do this myself.

    TL;DR: If you want to access the Yahoo Fantasy API just use this NodeJS tool I've created: https://github.com/edwarddistel/yahoo-fantasy-baseball-reader

    If you want to create your own app in NodeJS or PHP however, here's how:

    1. Go to https://developer.yahoo.com/apps/create/, get a Consumer Key and Consumer Secret

    2. Put the Consumer Key into https://api.login.yahoo.com/oauth2/request_auth?client_id=YOUR-CONSUMER-KEY-GOES-HERE&redirect_uri=oob&response_type=code&language=en-us and Agree to allow access, then grab the authorization code

    3. Construct the Auth header, a Base64 encoding of CONSUMER_KEY:CONSUMER_SECRET:

    const AUTH_HEADER = Buffer.from(`${CONSUMER_KEY}:${CONSUMER_SECRET}`, `binary`).toString(`base64`);
    
    1. Yahoo requires x-www-form-urlencoded, so if using an HTTP request library like Axios you'll need to stringify the data as per the docs

    2. Make a request to Yahoo. Here's an example:

    function getInitialAuthorization () {
        return axios({
            url: `https://api.login.yahoo.com/oauth2/get_token`,
            method: 'post',
            headers: {
                'Authorization': `Basic ${AUTH_HEADER}`,
                'Content-Type': 'application/x-www-form-urlencoded',
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
            },
            data: qs.stringify({
                client_id: CONSUMER_KEY,
                client_secret: CONSUMER_SECRET,
                redirect_uri: 'oob',
                code: YAHOO_AUTH_CODE,
                grant_type: 'authorization_code'
            }),
            timeout: 1000,
            }).catch((err) => {
                console.error(`Error in getInitialAuthorization(): ${err}`);
            });
    }
    
    1. Take that response and write it to a file. You'll need those credentials to re-authorize the app every 60 minutes of usage.

    2. Make normal HTTP requests to the Yahoo API. Check the response, if the authorization token has expired, re-authorize using a slightly different set of parameters:

    function refreshAuthorizationToken (token) {
        return axios({
            url: `https://api.login.yahoo.com/oauth2/get_token`,
            method: 'post',
            headers: {
                'Authorization': `Basic ${AUTH_HEADER}`,
                'Content-Type': 'application/x-www-form-urlencoded',
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
            },
            data: qs.stringify({
                redirect_uri: 'oob',
                grant_type: 'refresh_token',
                refresh_token: token
            }),
            timeout: 10000,
        }).catch((err) => {
            console.error(`Error in refreshAuthorizationToken(): ${err}`);
        });       
    }
    
    1. An example of making an API request and checking authorization:
    // Hit the Yahoo Fantasy API
    async function makeAPIrequest (url) {
        let response;
        try {
            response = await axios({
            url: url,
                method: 'get',
                headers: {
                    'Authorization': `Bearer ${CREDENTIALS.access_token}`,
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
                },
                timeout: 10000,
            });
            const jsonData = JSON.parse(parser.toJson(response.data));
            return jsonData;
        } catch (err) {
            if (err.response.data && err.response.data.error && err.response.data.error.description && err.response.data.error.description.includes("token_expired")) {
                const newToken = await refreshAuthorizationToken(CREDENTIALS.refresh_token);
                if (newToken && newToken.data && newToken.data.access_token) {
                    CREDENTIALS = newToken.data;
                    // Just a wrapper for fs.writeFile
                    writeToFile(JSON.stringify(newToken.data), AUTH_FILE, 'w');
                    return makeAPIrequest(url, newToken.data.access_token, newToken.data.refresh_token);
    
                 }
            } else {
                console.error(`Error with credentials in makeAPIrequest()/refreshAuthorizationToken(): ${err}`);
                process.exit();
            }
        }
    }
    

    Here is an example in PHP:

    function getInitialAuthorizationToken() {
    
        $ch = curl_init();
    
        $post_values = [
            "client_id" => $GLOBALS['consumer_key'],
            "client_secret" => $GLOBALS['consumer_secret'],
            "redirect_uri" => "oob",
            "code" => $GLOBALS['initial_auth_code'],
            "grant_type" => "authorization_code"
        ];
    
        curl_setopt_array($ch, array(
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_URL => $GLOBALS['auth_endpoint'],
            CURLOPT_POST => 1,
            CURLOPT_HTTPHEADER => array(
            'Authorization: Basic ' . $GLOBALS['auth_header'],
            'Content-Type: application/x-www-form-urlencoded',
            'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'),
            CURLOPT_POSTFIELDS => http_build_query($post_values)
        ));
    
        $answer = curl_exec($ch);
        if (isset($answer)) writeToFile($answer);
    
        if (!isset($access_token)) {
            echo "Error!";
            die;
    
        }
        else {
            return $token;
        }
    
    }
    

    Hope this helps others.