as YouTube v2 API is getting deprecated I need to migrate to v3.
With v2 I used the also deprecated ClientLogin (http://bit.ly/v2_ClientLogin_authentification) authentication method to authenticate and then upload user videos to my YouTube channel.
With v3 I tried to authenticate with a service account, with the same codebase used here
PHP Youtube API v3 - Direct Upload - Unauthorized message
and I'm getting the same error message from the API endpoint:
Error calling POST https://www.googleapis.com/youtube/v3/videos?part=status%2Csnippet: (401) Unauthorized
I also checked via Google's tokeninfo (https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=[ACCESS_TOKEN]) that the access token is valid:
{
"issued_to": "***.apps.googleusercontent.com",
"audience": "***.apps.googleusercontent.com",
"scope": "https://www.googleapis.com/auth/youtube",
"expires_in": 3592,
"access_type": "offline"
}
All YouTube examples I found are based on OAuth2 and user authorization. (like this one here: http://bit.ly/yt-api-example-videoupload). But that's not the way I want: The user shouldn't see any "Please authorize whatever.de to upload YouTube videos" AND the videos should be uploaded to my YT channel instead of theirs.
If there's no possibilty to use an API service account for that, could you please give me a hint how to do that with OAuth2? :-)
Here's my current code:
/** Config */
$private_key_password = 'notasecret';
$private_key_file = '***.p12';
$applicationName = '***';
$client_secret = '***'; // <--- WHERE IS THAT CLIENT_SECRET COMING FROM? Secret accounts do not have a client secret?
$client_id = '***.apps.googleusercontent.com';
$service_mail = '***@developer.gserviceaccount.com';
$scope = 'https://www.googleapis.com/auth/youtube';
$url_youtube_token = 'https://accounts.google.com/o/oauth2/token';
$jwt = new Google_Auth_AssertionCredentials($service_mail, $scope, $private_key_file, $private_key_password, $url_youtube_token);
$jwt_assertion = $jwt->generateAssertion();
$data = array
(
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion' => $jwt_assertion,
);
$options = array
(
'http' => array
(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
),
);
$context = stream_context_create($options);
$result = file_get_contents($url_youtube_token, false, $context);
//var_dump($result); die();
try{
// Client init
$client = new Google_Client();
$client->setClientId($client_id);
//$client->setClientSecret($client_secret); // <-- See above
$client->setApplicationName($applicationName);
$client->setAccessToken($result);
if ($client->getAccessToken())
{
if($client->isAccessTokenExpired())
{
// @TODO Log error
echo 'Access Token Expired!!<br/>'; // Debug
}
$youtube = new Google_Service_Youtube($client);
$videoPath = "./test.mp4";
// Create a snipet with title, description, tags and category id
$snippet = new Google_Service_YouTube_VideoSnippet();
$snippet->setTitle("fmgonzalez test " . time());
$snippet->setDescription("fmgonzalez test " . time() );
$snippet->setTags(array("tag1", "tag2"));
// Numeric video category. See
// https://developers.google.com/youtube/v3/docs/videoCategories/list
$snippet->setCategoryId("22");
// Create a video status with privacy status. Options are "public", "private" and "unlisted".
$status = new Google_Service_YouTube_VideoStatus();
$status->privacyStatus = "public";
// Create a YouTube video with snippet and status
$video = new Google_Service_YouTube_Video();
$video->setSnippet($snippet);
$video->setStatus($status);
// Size of each chunk of data in bytes. Setting it higher leads faster upload (less chunks,
// for reliable connections). Setting it lower leads better recovery (fine-grained chunks)
$chunkSizeBytes = 1 * 1024 * 1024;
// Create a MediaFileUpload with resumable uploads
$insertRequest = $youtube->videos->insert("status,snippet", $video);
$media = new Google_Http_MediaFileUpload
(
$client,
$insertRequest,
'video/*',
null,
true,
$chunkSizeBytes
);
$media->setFileSize(filesize($videoPath));
// Create a video insert request
$insertResponse = $youtube->videos->insert("status,snippet", $video,
array('mediaUpload' => $media));
$uploadStatus = false;
// Read file and upload chunk by chunk
$handle = fopen($videoPath, "rb");
$cont = 1;
while (!$uploadStatus && !feof($handle))
{
$chunk = fread($handle, $chunkSizeBytes);
$uploadStatus = $media->nextChunk($insertResponse, $chunk);
echo 'Chunk ' . $cont . ' uploaded <br/>';
$cont++;
}
fclose($handle);
echo '<br/>OK<br/>';
}
else
{
// @TODO Log error
echo 'Problems creating the client';
}
}
catch(Google_Service_Exception $e)
{
print "Caught Google service Exception ".$e->getCode(). " message is <br>".$e->getMessage(). " <br>";
//print "Stack trace is ".$e->getTraceAsString();
}
catch (Exception $e)
{
echo $e->getMessage();
}
?>
It is not possible to access the YouTube API with a service account
Issue 5370: Youtube v3 Google Service Account Access
You will need to use Oauth2 You will only need to authenticate once. Save your refresh token using offline access. then you can use that to run your script.
$client->setAccessType('offline'); // Gets us our refreshtoken
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With