質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

Google Calendar APIで、access token取得後、ユーザーのデータを取得できるまでに約20分のタイムラグがある。

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 1,751

Delpy

score 33

前提・実現したいこと

Laravel5.1を使い、Google Calendar APIでWebアプリを作っています。  
ユーザー認証まではできたのですが、ユーザーのデータ取得でつまづいています。

発生している問題

OAuth -> access token取得まではできています。有効なaccess tokenを使っています。
しかし、そのaccess tokenでユーザーのデータを取得しようとすると、下記のエラーが出ます。
ところが、約20分経つと、エラーは出ず、ユーザーのデータ取得に成功します。
このタイムラグは一体何が原因なのでしょうか。

エラーメッセージ

Google_Service_Exception in REST.php line 123:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "authError",
"message": "Invalid Credentials",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Invalid Credentials"
}
}

ソースコード

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use Google_Service_Calendar;
use Exception;
use Google_Client;
use Redirect;

class GoogleLoginController extends Controller
{

  public function initial(){
      require_once base_path() . '/vendor/autoload.php';

      session_start();


      $client = new Google_Client();
      $client->setAuthConfigFile(base_path() . '/client_secret.json');
      $client->addScope(Google_Service_Calendar::CALENDAR_READONLY);

      // $_SESSIONにaccess_tokenがあるならば
      if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {

        $client->setAccessToken($_SESSION['access_token']);

        $options = array(
        CURLOPT_RETURNTRANSFER => true,   // return web page
        CURLOPT_HEADER         => false,  // don't return headers
        CURLOPT_FOLLOWLOCATION => true,   // follow redirects
        CURLOPT_MAXREDIRS      => 10,     // stop after 10 redirects
        CURLOPT_ENCODING       => "",     // handle compressed
        CURLOPT_USERAGENT      => "test", // name of client
        CURLOPT_AUTOREFERER    => true,   // set referrer on redirect
        CURLOPT_CONNECTTIMEOUT => 120,    // time-out on connect
        CURLOPT_TIMEOUT        => 120,    // time-out on response
        ); 
        $current_access_token = $_SESSION['access_token']['access_token'];
        $ch = curl_init('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' . $current_access_token);
        curl_setopt_array($ch, $options);
        $content  = curl_exec($ch);
        curl_close($ch);

        $decoded_content_object = json_decode($content);

        // access tokenが有効ならば
        if (isset($decoded_content_object->issued_to)) {

          $service = new Google_Service_Calendar($client);
          // 設定日時(2015-09-01T00:00:00+09:00)から3つのイベントをプリント
          $calendarId = 'primary';
          $optParams = array(
            'maxResults' => 3,
            'orderBy' => 'startTime',
            'singleEvents' => TRUE,
            'timeMin' => '2015-09-01T00:00:00+09:00',
            );
          $results = $service->events->listEvents($calendarId, $optParams);
          $events = $results->getItems();
          foreach ($events as $key => $event) {
            echo $event->getSummary(); echo "<br>";
            echo $event->getLocation(); echo "<br>";
            echo $event->start->dateTime; echo "<br>";
            echo $event->end->dateTime; echo "<br>";
          }
        // access tokenが有効でないならば
        } elseif (isset($decoded_content_object->error)) {

          // access tokenが有効期限切れならば
          if ($client->isAccessTokenExpired()) {

            $refresh_token = '1/lsWyz_Tvf8R0s2ab8Fg7f7rfxiYN25ooercB47hVCctIgOrJDtdun6zK6XiATCKT';

            // refreshToken()が失敗したならばsessionを削除し、再度認証へ
            if (isset($client->refreshToken($refresh_token)['error'])) {

              $_SESSION = array();
              if (ini_get("session.use_cookies")) {
                $params = session_get_cookie_params();
                setcookie(session_name(), '', time() - 42000,
                $params["path"], $params["domain"],
                $params["secure"], $params["httponly"]
                );
              }
              session_destroy();

              $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback';
              header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
              exit;
            }

            $client->refreshToken($refresh_token);

            $service = new Google_Service_Calendar($client);

            // Print the next 10 events on the user's calendar.
            $calendarId = 'primary';
            $optParams = array(
            'maxResults' => 1,
            'orderBy' => 'startTime',
            'singleEvents' => TRUE,
            'timeMin' => '2015-09-01T00:00:00+09:00',
            );
            $results = $service->events->listEvents($calendarId, $optParams);
            $events = $results->getItems();
            foreach ($events as $key => $event) {
                echo $event->getSummary();
                echo $event->getLocation();
                echo $event->start->dateTime;
                echo $event->end->dateTime;
            }
          // ユーザーがでアクセス許可を無効にしたならば
          } else {

            $_SESSION = array();
            if (ini_get("session.use_cookies")) {
              $params = session_get_cookie_params();
              setcookie(session_name(), '', time() - 42000,
              $params["path"], $params["domain"],
              $params["secure"], $params["httponly"]
              );
            }
            session_destroy();

            $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback';
            header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
            exit;
          }
        // その他のエラー
        } else {
            return "unknown error";
        }
      // $_SESSIONにaccess tokenがないならば
      } else {
          $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback';
          header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
          exit;
  }
}

public function callback(){
    require_once base_path() . '/vendor/autoload.php';

    session_start();

    $client = new Google_Client();
    $client->setAuthConfigFile(base_path() . '/client_secret.json');
    $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback');
    $client->addScope(Google_Service_Calendar::CALENDAR_READONLY);
    $client->setAccessType('offline');

    if (!isset($_GET['code'])) {
      $auth_url = $client->createAuthUrl();
      header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
      exit;
    } else {
      $client->authenticate($_GET['code']);
      $access_token = $client->getAccessToken();
      $refresh_token = $client->getRefreshToken();
      $_SESSION['access_token'] = $access_token;
      $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/calendars';
      header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
      exit;
    }
}

補足情報

言語: PHP 5.6.13
フレームワーク: Laravel 5.1

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

Googleのオフィシャルドキュメントに下記のような記述がありました。
Note: Following a successful revocation response, it might take some time before the revocation has full effect.

すなわちrevokeには少し時間がかかる場合があるということです。それが、今回の私の環境では約20分であると考えられます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる