OAuth 2.0認証を行ってYouTube Data API v3を利用するための手順は、
- OAuth同意画面の設定
- OAuthクライアントIDの作成
- Googleの承認サーバーURLにアクセスして、アプリケーションにAPIの実行を許可&承認コードを取得
- 承認コードを使ってアクセストークンを取得
- 期限が切れた場合、更新トークンを使って新しいアクセストークンを取得
となる。
まず、Google Cloud Platform上でOAuth同意画面を設定する。
Google Cloud Platformの "APIとサービス" → "OAuth同意画面" ページに移動して下記の設定を行う。
※この設定は、プレイリストのインポート機能の開発テスト用にAPIを利用することを前提にしている
- ユーザーの種類を選択する。
G Suiteを利用していれば "内部" の選択が可能。利用していなければ "外部" を選択することになる。
※G Suiteのアカウントから作成されたものであってもYouTubeブランドアカウントはG Suiteの組織内ユーザーとみなされない。よって、YouTubeブランドアカウントのデータをAPIから操作したい場合は "外部" を選択する必要がある。
- アプリケーション名を入力する
- スコープの追加
./auth/youtube
を追加する。(APIでプレイリストの作成をリクエストするために必要)
- 保存
次に、Google Cloud Platform上でOAuthクライアントIDを作成する。
Google Cloud Platformの "APIとサービス" → "OAuth同意画面" ページに移動する。
- "+認証情報を作成" をクリック
- "OAuth クライアント ID" を選択
- アプリケーションの種類 "デスクトップアプリ" を選択
- 作成
以上で、Google Cloud Platform上で行う設定は完了。
続いて、承認コードを取得する。承認コードを取得するには、Googleの承認サーバーURLにアクセスする必要がある。
下記は、Googleの承認サーバーURLを表示するためのコード。
require_once '/path/to/google-api-php-client/vendor/autoload.php';
$CLIENT_ID = '_CLIENT_ID_';
$CLIENT_SECRET = '_CLIENT_SECRET_';
$REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob';
$client = new Google_Client();
$client->setClientId($CLIENT_ID);
$client->setClientSecret($CLIENT_SECRET);
$client->setRedirectUri($REDIRECT_URI);
$client->setAccessType('offline');
$client->setScopes('https://www.googleapis.com/auth/youtube');
echo $client->createAuthUrl() . "\n";
上記コードで行っているのは、クライアントライブラリを使い、Googleの承認サーバーURLに含めるリクエストパラメータを設定し、最後に createAuthUrl()
でそのURLを表示している。
setClientId()
と setClientSecret()
には、Google Cloud Platform上で作成したOAuthクライアントIDとクライアントシークレットをそれぞれセットする。
setRedirectUri()
には、Googleの承認サーバーが承認コードを返す先を指定する。urn:ietf:wg:oauth:2.0:oob
を指定すると、コードはブラウザのタイトルバーに返される。
※実際はGoogleの承認サーバーのページ上にも表示される(後述)
setAccessType()
で、リクエストパラメータ access_type
の値をセットする。offline
は、Googleの承認サーバーがアクセストークンを返す際に一緒に更新トークンも返すことを指定するもの(後述)。
setScopes()
で、リクエストパラメータ scope
の値をセットする。https://www.googleapis.com/auth/youtube
は、Google Cloud Platform上のOAuth同意画面の設定で追加したスコープ ./auth/youtube
に該当する。
上記コードを実行すると下記のようなURLが表示される。
https://accounts.google.com/o/oauth2/auth?response_type=code&access_type=offline&client_id=xxx&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&state&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube&approval_prompt=auto
このURLにWebブラウザでアクセスし、承認コードを取得する。
- アクセス権を付与するアカウントを選択
- "許可" をクリック
※「このアプリは確認されていません」と表示される場合(OAuth同意画面の設定でユーザーの種類に "外部" を選択した場合)
- 左下の "詳細を表示" をクリック
- "<OAuth同意画面の設定で入力したアプリケーション名>(安全ではないページ)に移動" をクリック
- "許可" をクリック
- 「このコードをコピーし、アプリケーションに切り替えて貼り付けてください。」とページ上に表示されている承認コードをコピー
続いて、取得した承認コードを使ってアクセストークンを取得する。
require_once '/path/to/google-api-php-client/vendor/autoload.php';
$CLIENT_ID = '_CLIENT_ID_';
$CLIENT_SECRET = '_CLIENT_SECRET_';
$REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob';
$CODE = '_CODE_'; // ここに承認コードを貼り付ける
$TOKEN_FILENAME = "token.json";
$client = new Google_Client();
$client->setClientId($CLIENT_ID);
$client->setClientSecret($CLIENT_SECRET);
$client->setRedirectUri($REDIRECT_URI);
$client->setAccessType('offline');
$client->setScopes('https://www.googleapis.com/auth/youtube');
$tokenArray = $client->fetchAccessTokenWithAuthCode($CODE);
$tokenJson = json_encode($tokenArray);
file_put_contents($TOKEN_FILENAME, $tokenJson);
$youtube = new Google_Service_YouTube($client);
// 以降、$youtubeを使ってAPIリクエストを行える
fetchAccessTokenWithAuthCode($CODE)
で承認コードを使ってアクセストークンを取得する。このメソッドは短期間有効なアクセストークンと更新トークンを含む配列を返す。
※承認コードを取得する際、リクエストパラメータ access_type
に offline
を指定したので更新トークンも取得されることに留意
このトークンはAPIリクエストを行う際に毎回必要になるので、今後の開発テスト実行時のためにJSON形式でファイルに保存しておく。
※トークンを保存しておかないと、OAuth 2.0の同意フローを再度行ってアクセストークンを取得しなければならない
今後の実行時には、ファイルに保存したトークンのリストア、また、アクセストークンは定期的に期限切れになるので、更新トークンを使った新しいアクセストークンの取得が必要になる。
下記がそれを行うコードになる。
require_once '/path/to/google-api-php-client/vendor/autoload.php';
$CLIENT_ID = '_CLIENT_ID_';
$CLIENT_SECRET = '_CLIENT_SECRET_';
$REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob';
$CODE = '_CODE_';
$TOKEN_FILENAME = "token.json";
$client = new Google_Client();
$client->setClientId($CLIENT_ID);
$client->setClientSecret($CLIENT_SECRET);
$client->setRedirectUri($REDIRECT_URI);
$client->setAccessType('offline');
$client->setScopes('https://www.googleapis.com/auth/youtube');
$tokenJson = file_get_contents($TOKEN_FILENAME);
$client->setAccessToken($tokenJson);
if ($client->isAccessTokenExpired())
{
$newTokenArray = $client->fetchAccessTokenWithRefreshToken();
$newTokenJson = json_encode($newTokenArray);
file_put_contents($TOKEN_FILENAME, $newTokenJson);
}
$youtube = new Google_Service_YouTube($client);
// 以降、$youtubeを使ってAPIリクエストを行える
ファイルから読み込んだJSON形式のトークン情報は、setAccessToken()
を使ってクライアント上にリストアできる。
アクセストークンの期限切れは isAccessTokenExpired()
で確認できる。期限切れの場合は、fetchAccessTokenWithRefreshToken()
を使う。このメソッドにより、更新トークンを使って新しいアクセストークンが取得することができる。
トークンが更新された場合、また次回実行時のためにJSON形式でファイルに保存する。
最後に、上記3つのコードを OAuthClient
クラスとして書き直したものが下記。今後、実際に利用していくのはこのコードになる。
require_once '/path/to/google-api-php-client/vendor/autoload.php';
$CLIENT_ID = '_CLIENT_ID_';
$CLIENT_SECRET = '_CLIENT_SECRET_';
$REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob';
$TOKEN_FILENAME = "token.json";
$CODE = '_CODE_';
class OAuthClient
{
const EMPTY_CODE = 1;
const INVALID_CODE = 2;
const INVALID_TOKEN_FILE = 3;
private $client;
private $code;
private $tokenFileName;
public function __construct(Google_Client $client, $clientId, $clientSecret, $redirectUri, $tokenFileName = "token.json", $code = "")
{
$this->client = $client;
$this->client->setClientId($clientId);
$this->client->setClientSecret($clientSecret);
$this->client->setRedirectUri($redirectUri);
$this->client->setAccessType('offline');
$this->tokenFileName = $tokenFileName;
$this->code = $code;
}
public function setScopes($scope_or_scopes)
{
$this->client->setScopes($scope_or_scopes);
}
public function getAuthUrl()
{
return $this->client->createAuthUrl();
}
public function getAuthorizedClient()
{
if (empty($this->code))
{
throw new Exception("Get a code. (Remove the \"{$this->tokenFileName}\" file if it exists.)", self::EMPTY_CODE);
}
if (!file_exists($this->tokenFileName))
{
$tokenArray = $this->client->fetchAccessTokenWithAuthCode($this->code);
if (!isset($tokenArray['access_token']))
{
throw new Exception("Invalid code. Get a new code.", self::INVALID_CODE);
}
$this->storeAccessToken($tokenArray);
}
else
{
$this->restoreAccessToken($this->tokenFileName);
}
return $this->client;
}
private function restoreAccessToken()
{
$tokenJson = file_get_contents($this->tokenFileName);
$tokenArray = json_decode($tokenJson, true);
if (!isset($tokenArray['access_token']))
{
throw new Exception( "Invalid file: \"{$this->tokenFileName}\". Remove the file, then execute the program again.", self::INVALID_TOKEN_FILE);
}
$this->client->setAccessToken($tokenJson);
if ($this->client->isAccessTokenExpired())
{
$newTokenArray = $this->client->fetchAccessTokenWithRefreshToken();
$this->storeAccessToken($newTokenArray);
fwrite(STDERR, "# " . __METHOD__ . ": Token updated.\n");
}
}
private function storeAccessToken(array $token)
{
$tokenJson = json_encode($token);
file_put_contents($this->tokenFileName, $tokenJson);
fwrite(STDERR, "# " . __METHOD__ . ": Token stored.\n");
}
}
try
{
$gclient = new Google_Client();
$oauth = new OAuthClient($gclient, $CLIENT_ID, $CLIENT_SECRET, $REDIRECT_URI, $TOKEN_FILENAME, $CODE);
$oauth->setScopes('https://www.googleapis.com/auth/youtube');
$client = $oauth->getAuthorizedClient();
}
catch(Exception $e)
{
switch($e->getCode())
{
case OAuthClient::EMPTY_CODE:
case OAuthClient::INVALID_CODE:
echo $e->getMessage() . "\n";
echo $oauth->getAuthUrl() . "\n";
exit;
case OAuthClient::INVALID_TOKEN_FILE:
echo $e->getMessage() . "\n";
exit;
default:
throw $e;
}
}
$youtube = new Google_Service_YouTube($client);
// 以降、$youtubeを使ってAPIリクエストを行える