Search code examples
phplaraveloauthoauth-2.0fitbit

Laravel OAuth Authorization Header for FitBit API


I have been struggling for days now to find a decent solution for Laravel but to no avail.

There are many libraries out there that at one point may have worked to provide a Laravel - FitBit API OAuth integration however after trying over 15 different ones and none of them working I am stuck.

Reading the FitBit Documentation I see that once you receive a token you must swap the authorization code with an access token. To do this you need to send an authorization header like this:

POST https://api.fitbit.com/oauth2/token
Authorization: Basic Y2xpZW50X2lkOmNsaWVudCBzZWNyZXQ=
Content-Type: application/x-www-form-urlencoded

client_id=22942C&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fexample.com%2Fcallback&code=1234567890

I have tried using guzzle and a few other libraries for sending the requests but none of them support the format that FitBit require.

I've seen sites with FitBit API integrated so there must be a solution for this.

If anyone has managed to integrate the FitBit API please let me know where I am going wrong.

Thanks.


Solution

  • I don't have a fitbit account, so I can't test this and it will probably need some tweaking, but I would start with something like:

    class FitbitConnection{
    
        public function getToken($request_url, $client_id, $client_secret, $code, $redirect_uri){
    
            // base64 encode the client_id and client_secret
            $auth = base64_encode("{$client_id}:{$client_secret}");
            // urlencode the redirect_url
            $redirect_uri = urlencode($redirect_uri);
            $request_url .= "?client_id={$client_id}&grant_type=authorization_code&redirect_uri={$redirect_uri}&code={$code}";
    
            // Set the headers
            $headers = [
                            "Authorization: Basic {$auth}",
                            "Content-Type: application/x-www-form-urlencoded",
                        ];
    
                // Initiate curl session
                $ch = curl_init();
                // Set headers
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
                // Options (see: http://php.net/manual/en/function.curl-setopt.php)
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
                curl_setopt($ch, CURLOPT_VERBOSE, 1);
                curl_setopt($ch, CURLOPT_HEADER, 1);
                curl_setopt($ch, CURLOPT_URL, $request_url);
                curl_setopt($ch, CURLOPT_POST, 1);
                // Execute the curl request and get the response
                $response = curl_exec($ch);
    
                // Throw an exception if there was an error with curl
                if($response === false){
                    throw new Exception(curl_error($ch), curl_errno($ch));
                }
    
                // Get the body of the response
                $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
                $responseBody = substr($response, $header_size);
                // Close curl session
                curl_close($ch);
    
                // Return response body
                return $responseBody;
    
        }
    }
    

    You should note that I've commented out

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

    You can put this option back in if you get an SSL certificate problem on your localhost, but you shouldn't use it in production .

    You can then just do something like:

    try{
        $fitbitConnection = new FitbitConnection();
        $token_response = $fitbitConnection->getToken("https://api.fitbit.com/oauth2/token","22942C","client_secret","1234567890","http://www.example.com");
        echo $token_response;
    }catch(Exception $e){
        // curl error
        echo $e->getMessage();
    }