Skip to content
Advertisement

Fitbit Auth 2 Api integration without Token expired

Currently, I am working/integrating Fitbit API on my Yii2 framework.

Code sample like this:

if($_SERVER['HTTP_HOST'] == 'localhost'){
    define('REDIRECT_URI', 'https://localhost/yii/contest/FitbitDeviceChange');
}else{
    define('REDIRECT_URI', "https://".$_SERVER['HTTP_HOST']."/site/SocialSiteFitfit");
}
define('HOST', 'https://api.fitbit.com/');
define('ACCESS_TOKEN_URL', 'https://api.fitbit.com/oauth2/token');
define('AUTHENTICATE_URL', 'https://www.fitbit.com/oauth2/authorize');

class FitbitApiController extends FrontController {
    private $accessToken = null;
    private $refreshToken = null;
    private $expires = 31536000;
    public $CLIENT_ID = '';
    public $CLIENT_SECRET = '';
    public $REDIRECT_URI = REDIRECT_URI;

    /**
    * fn getAuthorizationCode() launch the authorization page
    *
    */
    public static function getAuthorizationCode($CLIENT_ID) {
        $url = AUTHENTICATE_URL.'?response_type=code&prompt=login consent&client_id='.$CLIENT_ID.
            '&redirect_uri='.urlencode(REDIRECT_URI).
            '&scope=activity%20profile&expires_in=31536000';
        header('Location: '.$url);
    }
}

API Integration is currently done and working fine, but after a certain time token expired, I never want customers again and again to accept a request, I want customers to accept requests once and never expired token and not need to connect again and again.

Any Idea how to prevent token expiration?

My refresh code URL is: https://github.com/namelivia/fitbit-http-php

Advertisement

Answer

You can use URL ‘https://api.fitbit.com/oauth2/revoke’ and your existing access_token for refresh or regenerate.

public function revoke(AccessToken $accessToken)
{
    $options = $this->getOptionProvider()
        ->getAccessTokenOptions(self::METHOD_POST, []);

    $uri = $this->appendQuery(
        'https://api.fitbit.com/oauth2/revoke/oauth2/revoke',
        $this->buildQueryString(['token' => $accessToken->getToken()])
    );
    $request = $this->getRequest(self::METHOD_POST, $uri, $options);

    return $this->getResponse($request);
}

Full Example are:

<?php

namespace djchenOAuth2ClientProvider;

use LeagueOAuth2ClientProviderAbstractProvider;
use LeagueOAuth2ClientProviderExceptionIdentityProviderException;
use LeagueOAuth2ClientTokenAccessToken;
use LeagueOAuth2ClientToolBearerAuthorizationTrait;
use PsrHttpMessageResponseInterface;

class Fitbit extends AbstractProvider
{
    use BearerAuthorizationTrait;

    /**
     * Fitbit URL.
     *
     * @const string
     */
    const BASE_FITBIT_URL = 'https://www.fitbit.com';

    /**
     * Fitbit API URL.
     *
     * @const string
     */
    const BASE_FITBIT_API_URL = 'https://api.fitbit.com';

    /**
     * HTTP header Accept-Language.
     *
     * @const string
     */
    const HEADER_ACCEPT_LANG = 'Accept-Language';

    /**
     * HTTP header Accept-Locale.
     *
     * @const string
     */
    const HEADER_ACCEPT_LOCALE = 'Accept-Locale';

    /**
     * Overridden to inject our options provider
     * @param array $options
     * @param array $collaborators
     */
    public function __construct(array $options = [], array $collaborators = [])
    {
        $collaborators['optionProvider'] = new FitbitOptionsProvider(
            $options['clientId'],
            $options['clientSecret']
        );
        parent::__construct($options, $collaborators);
    }

    /**
     * Get authorization url to begin OAuth flow.
     *
     * @return string
     */
    public function getBaseAuthorizationUrl()
    {
        return static::BASE_FITBIT_URL.'/oauth2/authorize';
    }

    /**
     * Get access token url to retrieve token.
     *
     * @param array $params
     *
     * @return string
     */
    public function getBaseAccessTokenUrl(array $params)
    {
        return static::BASE_FITBIT_API_URL.'/oauth2/token';
    }

    /**
     * Returns the url to retrieve the resource owners's profile/details.
     *
     * @param AccessToken $token
     *
     * @return string
     */
    public function getResourceOwnerDetailsUrl(AccessToken $token)
    {
        return static::BASE_FITBIT_API_URL.'/1/user/-/profile.json';
    }

    /**
     * Returns all scopes available from Fitbit.
     * It is recommended you only request the scopes you need!
     *
     * @return array
     */
    protected function getDefaultScopes()
    {
        return ['activity', 'heartrate', 'location', 'profile', 'settings', 'sleep', 'social', 'weight', 'nutrition'];
    }

    /**
     * Checks Fitbit API response for errors.
     *
     * @throws IdentityProviderException
     *
     * @param ResponseInterface $response
     * @param array|string      $data     Parsed response data
     */
    protected function checkResponse(ResponseInterface $response, $data)
    {
        if ($response->getStatusCode() >= 400) {
            $errorMessage = '';
            if (!empty($data['errors'])) {
                foreach ($data['errors'] as $error) {
                    if (!empty($errorMessage)) {
                        $errorMessage .= ' , ';
                    }
                    $errorMessage .= implode(' - ', $error);
                }
            } else {
                $errorMessage = $response->getReasonPhrase();
            }
            throw new IdentityProviderException(
                $errorMessage,
                $response->getStatusCode(),
                $response
            );
        }
    }

    /**
     * Returns the string used to separate scopes.
     *
     * @return string
     */
    protected function getScopeSeparator()
    {
        return ' ';
    }

    /**
     * Returns authorization parameters based on provided options.
     * Fitbit does not use the 'approval_prompt' param and here we remove it.
     *
     * @param array $options
     *
     * @return array Authorization parameters
     */
    protected function getAuthorizationParameters(array $options)
    {
        $params = parent::getAuthorizationParameters($options);
        unset($params['approval_prompt']);
        if (!empty($options['prompt'])) {
            $params['prompt'] = $options['prompt'];
        }

        return $params;
    }

    /**
     * Generates a resource owner object from a successful resource owner
     * details request.
     *
     * @param array       $response
     * @param AccessToken $token
     *
     * @return FitbitUser
     */
    public function createResourceOwner(array $response, AccessToken $token)
    {
        return new FitbitUser($response);
    }

    /**
     * Returns the key used in the access token response to identify the resource owner.
     *
     * @return string|null Resource owner identifier key
     */
    protected function getAccessTokenResourceOwnerId()
    {
        return 'user_id';
    }

    /**
     * Revoke access for the given token.
     *
     * @param AccessToken $accessToken
     *
     * @return mixed
     */
    public function revoke(AccessToken $accessToken)
    {
        $options = $this->getOptionProvider()
            ->getAccessTokenOptions(self::METHOD_POST, []);

        $uri = $this->appendQuery(
            self::BASE_FITBIT_API_URL.'/oauth2/revoke',
            $this->buildQueryString(['token' => $accessToken->getToken()])
        );
        $request = $this->getRequest(self::METHOD_POST, $uri, $options);

        return $this->getResponse($request);
    }

    public function parseResponse(ResponseInterface $response)
    {
        return parent::parseResponse($response);
    }

    /**
     * Parse Fitbit API Rate Limit headers and return a FitbitRateLimit object.
     *
     * @param ResponseInterface $response
     *
     * @return FitbitRateLimit Fitbit API Rate Limit information
     */
    public function getFitbitRateLimit(ResponseInterface $response)
    {
        return new FitbitRateLimit($response);
    }
}

You should read fitbit auth2 document also for more details about parameters: https://dev.fitbit.com/build/reference/web-api/oauth2/

and check full code : https://github.com/djchen/oauth2-fitbit/tree/master/src/Provider

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement