Authenticate code grant flow で FitbitAPI からデータを取得する例

Fitbit APIからデータを取得するためには OAuth2 をパスする必要がある。FitbitAPI は以下の2つのflowをサポートしている。

  • Authenticate grant flow
  • implicit grant flow

ドキュメントでは、サーバサイドコードからFitbitAPIにアクセスする場合、Authenticate grant flow が推奨されている。
このエントリでは、djchen/oauth2 というoauth2クライアントを利用して、Authenticate grant flow をパスするサンプルを作成してみる。

  • composerによるoauth2クライアント(djchen/oauth2)の導入手順
  • dev.fitbit.comへのサンプルアプリ登録
  • FitbitのOAuth2認証をパスするためのサンプル実装
  • Fitbitからサンプルデータの取得

composerによるoauth2クライアントの導入手順

phpスクリプトをブラウザから叩ける環境を用意する。VagrantでもVPSでも何でも。
~/wwwが DocumentRoot となるように httpd を構成する。

$ pwd
/home/ikuty/www

次に、composerを使ってOAuth2クライアントをインストールする。

$ composer require league/oauth2-client djchen/oauth2-fitbit

dev.fitbit.comへのサンプルアプリ登録

これから作るサンプルアプリを dev.fitbit.com に登録する必要がある。
例えば以下のような登録を行う。

  • Application Name: Test Application
  • Description: This is my first test.
  • Application Web Site: http://hoge.com:8001
  • Organization: Personal
  • Organization Web Site: https://ikuty.com/
  • OAuth2.0 Application Type: Personal
  • Callback URL: http://hoge.com:8001/test.php
  • Default Data Access: readonly

すると、以下を発行してもらえる。

  • OAUth 2.0 Client ID
  • Client Secret
  • OAuth 2.0: Authorization URI
  • OAUth 2.0: Access/Refresh Token Request URI

FitbitのOAuth2認証をパスするためのサンプル実装

サンプル実装、といっても本家のサンプルをそのまま流用しただけだが…。
以下の Authenticate grant flow の流れの通りとなっている。

  • ClientID,ClientSecretを使用して認証コードを取得する
  • 認証コード を accessToken に変換する
  • accessToken の有効期限に達したら refreshToken を使って accessToken を更新する
$ pwd
/home/ikuty/www
$ vi test.php

中身は以下

<?php
require_once './vendor/autoload.php';
use djchen\OAuth2\Client\Provider\Fitbit;
use League\OAuth2\Client\Token\AccessToken;

   $provider = new Fitbit([
       'clientId' => '{client_id}',  // 登録時に取得したclientId
       'clientSecret' => '{clientSecret}', //登録時に取得したclientSecret
       'redirectUri' => 'http://hoge.com:8002/test.php'
   ]);

   session_start();
   if(!isset($_GET['code'])){
       $authorizationUrl = $provider->getAuthorizationUrl();
       $_SESSION['oauth2state'] = $provider->getState();
       header('Location: '.$authorizationUrl);
       exit;
   } elseif ( empty($_GET['state']) ||
           ($_GET['state'] != $_SESSION['oauth2state'])){
       unset($_SESSION['oauth2state']);
       exit('Invalid state');
   } else {
       try
       {
           $forceToAuth = false;
           $needToRewrite = false;
           $lines = file('token.txt',FILE_IGNORE_NEW_LINES);
           if (($lines == false) || (count($lines) == 0) || $forceToAuth)
           {
               echo 'authorization_code->';
               //ここで 認証コード と accessToken を交換する
               $accessToken = $provider->getAccessToken('authorization_code',['code'=>$_GET['code']]);
               $needToRewrite = true;
           } else {
               echo 'existing AccessToken->';
               $_accessToken = $lines[0];
               $_refreshToken = $lines[1];
               $_expiredToken = $lines[2];
               $accessToken = new AccessToken(['access_token'=>$_accessToken,
                                               'refresh_token'=>$_refreshToken,
                                               'expires_in'=>$_expiredToken]);
               // accessToken の有効期限に達したら refreshToken を使って新しい accessTokenを要求する
               if ($accessToken->hasExpired())
               {
                   echo 'refresh AccessToken->';
                   $refreshToken = $accessToken->getRefreshToken();
                   $accessToken = $provider->getAccessToken('refresh_token',['refresh_token'=>$refreshToken]);
                   $needToRewrite = true;
               }
           }
           if ($needToRewrite)
           {
               $file = fopen("token.txt","wb");
               fputs($file, $accessToken->getToken());
               fputs($file, "\n");
               fputs($file, $accessToken->getRefreshToken());
               fputs($file, "\n");
               fputs($file, $accessToken->getExpires());
               fputs($file, "\n");
               fputs($file, $accessToken->getResourceOwnerId());
               fputs($file, "\n");
               fclose($file);
           }
      } catch (Exception $e){

      }
  }

最初、「$accessToken->getToken()を保存しておいて次回利用時に使いまわす」具体的な方法が分からなかった。oauth2-client の AccessTokenクラスの実装を見ると、コンストラクタにアクセストークン等を渡してあげればインスタンス化できることがわかった。
アクセストークンの有効期限に達すると、hasExpired()メソッドがtrueを返すようになる。その場合、リフレッシュトークンを使って新しいアクセストークンを要求する。DBに保存しておいたアクセストークンを新しい値で上書きする。

Fitbitからサンプルデータの取得

RESTfulなAPIを指定することでデータが得られる。例えばユーザのプロフィールを取得するには以下の通りとする。厳密にAPIにパラメータを全て埋め込むタイプではなくログイン情報等のセッション情報も用いられるタイプ。以下では、user-idとして”-“を渡すとセッションにあるユーザIDが使われるようだ。

  $request = $provider->getAuthenticatedRequest(
                'GET',
                Fitbit::BASE_FITBIT_API_URL . '/1/user/-/profile.json',
                $accessToken,
                ['headers' => ['Accept-Language' => 'ja_JP'],['Accept-Locale' => 'ja_JP']]
            );
  $response = $provider->getResponse($request);
  var_dump($response);

シェアする

  • このエントリーをはてなブックマークに追加

フォローする