Get YouTube Refresh Token from OAuth 2.0 Playground

Getting a YouTube (or other Google product/service) refresh token using Google’s OAuth 2.0 Playground is easy. Just follow this brief tutorial.

Go to the OAuth 2.0 Playground. Within Step 1 (Select & authorize APIs), scroll down and click on YouTube Data API v3. Then click on https://www.googleapis.com/auth/youtube.upload. Then click Authorize APIs.

OAuth 2.0 Playground YouTube Data API v3

YouTube Data API v3 YouTube.Upload

You will now be taken to a screen that will inform you Google OAuth 2.0 Playground would like to Manage your YouTube videos. Click Allow.

Google OAuth 2.0 Playground Manage YouTube Videos

Make sure the checkbox is checked for Auto-refresh the token before it expires. Then click Exchange authorization code for tokens.

Exchange Authorization Code for Tokens Auto-Refresh

To the right, below Request / Response, copy the following code and save them to a file called token.txt.

{
"access_token": "bio3.afodsdsdfoidfdfiADFfdaiorgoeediodfdd.D_beQ-o7G2b_B4Q9BaTBNQAT",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "9/faioERi534oigf-H4bw-BER43Abmir4_3Qzj49Hsdi"
}

YouTube OAuth API Access Token

PHP YouTube Video Upload with Google API OAuth 2.0 V3

Uploading videos using Google’s OAuth 2.0 V3 YouTube API is easy. Just follow these steps, and you’ll be uploading videos to YouTube in no time.

Step 1: Make Sure You Have a YouTube Channel

Making sure you have a YouTube channel is the first step of this process. Otherwise, you won’t have a YouTube channel to upload your videos! If you don’t already have a YouTube channel, make one and continue to the next step below.

Step 2: New Google Developers Console Project

Create a new project at Google Developers Console. Click Enable and Manage APIs. Enter in any project name. Select Yes below “I agree that my use of any services and related APIs is subject to my compliance with the applicable Terms of Service.” Click Create.

Enable Manage APIs Google Developers Console

New Project Google Developers Console

Click YouTube Data API. Then click Enable API.

YouTube Data APIs Google OAuth 2.0 V3

Enable YouTube Data API v3

Click Credentials.

Google OAuth 2.0 V3 API Manager Credentials

Click OAuth consent screen. Enter in any value for product name shown to users (keep in mind this will show up to anyone accessing this API). Click Save.

OAuth Consent Screen YouTube Credentials

Click New credentials. Then click OAuth client ID.

New OAuth Client ID YouTube Credentials

Select Web application. Enter in any suitable name. Enter in the full URL of your Authorized redirect URIs. For this tutorial, I’ve used http://www.whitewareweb.com/api.php. Click Create.

YouTube Web Application Authorized Redirect URIs

Now you will be presented with your client ID and client secret. Copy these two values someplace safe for the upcoming steps and then click OK to dismiss the screen.

YouTube API OAuth Client ID Secret

Step 3: Install Composer & Google APIs Client Library for PHP

SSH into your server into the directory where you’ll have your script. For this example, I’m doing it on the root directory. Type in the following command to install composer:

php -r "readfile('https://getcomposer.org/installer');" | php

Then type in this command to install Google APIs Client Library for PHP:

php composer.phar require google/apiclient:^2.0.0@RC

Step 4: Get Access Token & Refresh Token

Create a file called token.php with the following code and upload it into your root directory or whichever directory you are using (make sure to change the values of $OAUTH2_CLIENT_ID and $OAUTH2_CLIENT_SECRET to the values you saved at the beginning of this tutorial):

<?php

require_once 'vendor/autoload.php';

session_start();

/*
 * You can acquire an OAuth 2.0 client ID and client secret from the
 * {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
 * For more information about using OAuth 2.0 to access Google APIs, please see:
 * <https://developers.google.com/youtube/v3/guides/authentication>
 * Please ensure that you have enabled the YouTube Data API for your project.
 */
$OAUTH2_CLIENT_ID = '344faiofosfdiiSFdisoiifASFDfdsoi3498dfSD.apps.googleusercontent.com'; // Enter your Client ID here
$OAUTH2_CLIENT_SECRET = 'aoier98_4389AoifioRF4'; // Enter your Client Secret here
$REDIRECT = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], FILTER_SANITIZE_URL);
$APPNAME = "WhiteWare Web";

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$client->setRedirectUri($REDIRECT);
$client->setApplicationName($APPNAME);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
    
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);

if (isset($_GET['code'])) {
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
        die('The session state did not match.');
    }

    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
}

if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
    echo "Access Token: " . json_encode($_SESSION['token']);
}

// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
    try {
        // Call the channels.list method to retrieve information about the
        // currently authenticated user's channel.
        $channelsResponse = $youtube->channels->listChannels('contentDetails', array('mine' => 'true'));

        $htmlBody = '';
        foreach ($channelsResponse['items'] as $channel) {
            // Extract the unique playlist ID that identifies the list of videos
            // uploaded to the channel, and then call the playlistItems.list method
            // to retrieve that list.
            $uploadsListId = $channel['contentDetails']['relatedPlaylists']['uploads'];

            $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                'playlistId' => $uploadsListId,
                'maxResults' => 50
            ));

            $htmlBody .= "<h3>Videos in list $uploadsListId</h3><ul>";
            foreach ($playlistItemsResponse['items'] as $playlistItem) {
                $htmlBody .= sprintf('<li>%s (%s)</li>', $playlistItem['snippet']['title'],
                    $playlistItem['snippet']['resourceId']['videoId']);
            }
            $htmlBody .= '</ul>';
        }
    } catch (Google_ServiceException $e) {
        $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    } catch (Google_Exception $e) {
        $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    }

    $_SESSION['token'] = $client->getAccessToken();
} else {
    $state = mt_rand();
    $client->setState($state);
    $_SESSION['state'] = $state;

    $authUrl = $client->createAuthUrl();
    $htmlBody = <<<END
<h3>Authorization Required</h3>
<p>You need to <a href="$authUrl">authorise access</a> before proceeding.<p>
END;
}
?>
 
<!doctype html>
<html>
<head>
    <title>My Uploads</title>
</head>
<body>
<?php echo $htmlBody;?>
</body>
</html>

My Uploads

Now, navigate to this newly created page in your browser (e.g. http://www.whitewareweb.com/token.php). Make sure you are logged on to your Google/YouTube account and authorize access when prompted. After authorizing access, you will be returned to the token page where your access token will be displayed in JSON format like this:

{"access_token": "bio3.afodsdsdfoidfdfiADFfdaiorgoeediodfdd.D_beQ-o7G2b_B4Q9BaTBNQAT","token_type": "Bearer","expires_in": 3600,"refresh_token": "9/faioERi534oigf-H4bw-BER43Abmir4_3Qzj49Hsdi"}

Copy the JSON code and save it to a file called token.txt.

Step 5: Upload a YouTube Video!

Upload token.txt into your root directory (or whichever directory you are using) and apply permissions of 600 on that file. Then create a file called api.php with the following code and upload it to this same directory (make sure to change the values of $OAUTH2_CLIENT_ID and $OAUTH2_CLIENT_SECRET to the values you saved at the beginning of this tutorial):

<?php

$key = file_get_contents('token.txt');

require_once 'vendor/autoload.php';

$client_id = '344faiofosfdiiSFdisoiifASFDfdsoi3498dfSD.apps.googleusercontent.com'; // Enter your Client ID here
$client_secret = 'aoier98_4389AoifioRF4'; // Enter your Client Secret here

$videoPath = "videos/example.mkv";
$videoTitle = "Just an Example Title";
$videoDescription = "This is the YouTube video's description";
$videoCategory = "22";
$videoTags = array("first tag","second tag","third tag");

try{
    // Client init
    $client = new Google_Client();
    $client->setClientId($client_id);
    $client->setAccessType('offline');
    $client->setApprovalPrompt('force');
    $client->setAccessToken($key);
    $client->setClientSecret($client_secret);

    if ($client->getAccessToken()) {
        /**
         * Check to see if our access token has expired. If so, get a new one and save it to file for future use.
         */
        if($client->isAccessTokenExpired()) {
            $newToken = json_decode($client->getAccessToken());
            $client->refreshToken($newToken->refresh_token);
            file_put_contents($key, $client->getAccessToken());
        }
 
        $youtube = new Google_Service_YouTube($client);
 
        // Create a snipet with title, description, tags and category id
        $snippet = new Google_Service_YouTube_VideoSnippet();
        $snippet->setTitle($videoTitle);
        $snippet->setDescription($videoDescription);
        $snippet->setCategoryId($videoCategory);
        $snippet->setTags($videoTags);
        $snippet->setDefaultLanguage("en");
        $snippet->setDefaultAudioLanguage("en");

        $recordingDetails = new Google_Service_YouTube_VideoRecordingDetails();
        $recordingDetails->setLocationDescription("United States of America");
        $recordingDetails->setRecordingDate("2016-01-20T12:34:00.000Z");
        $locationdetails = new Google_Service_YouTube_GeoPoint();
        $locationdetails->setLatitude("38.8833");
        $locationdetails->setLongitude("77.0167");
        $recordingDetails->setLocation($locationdetails);

        // Create a video status with privacy status. Options are "public", "private" and "unlisted".
        $status = new Google_Service_YouTube_VideoStatus();
        $status->setPrivacyStatus("public");
        $status->setPublicStatsViewable(false);
        $status->setEmbeddable(false); // Google defect still not editable https://code.google.com/p/gdata-issues/issues/detail?id=4861
 
        // Create a YouTube video with snippet and status
        $video = new Google_Service_YouTube_Video();
        $video->setSnippet($snippet);
        $video->setRecordingDetails($recordingDetails);
        $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;

        // Setting the defer flag to true tells the client to return a request which can be called
        // with ->execute(); instead of making the API call immediately.
        $client->setDefer(true);

        // Create a request for the API's videos.insert method to create and upload the video.
        $insertRequest = $youtube->videos->insert("status,snippet,recordingDetails", $video);

        // Create a MediaFileUpload object for resumable uploads.
        $media = new Google_Http_MediaFileUpload(
            $client,
            $insertRequest,
            'video/*',
            null,
            true,
            $chunkSizeBytes
        );
        $media->setFileSize(filesize($videoPath));

        // Read the media file and upload it chunk by chunk.
        $status = false;
        $handle = fopen($videoPath, "rb");
        while (!$status && !feof($handle)) {
            $chunk = fread($handle, $chunkSizeBytes);
            $status = $media->nextChunk($chunk);
        }

        fclose($handle);

        /**
         * Video has successfully been uploaded, now lets perform some cleanup functions for this video
         */
        if ($status->status['uploadStatus'] == 'uploaded') {
            // Actions to perform for a successful upload
        }

        // If you want to make other calls after the file upload, set setDefer back to false
        $client->setDefer(true);

    } else{
        // @TODO Log error
        echo 'Problems creating the client';
    }

} catch(Google_Service_Exception $e) {
    print "Caught Google service Exception ".$e->getCode(). " message is ".$e->getMessage();
    print "Stack trace is ".$e->getTraceAsString();
}catch (Exception $e) {
    print "Caught Google service Exception ".$e->getCode(). " message is ".$e->getMessage();
    print "Stack trace is ".$e->getTraceAsString();
}

?>

Now, navigate to this newly created page in your browser (e.g. http://www.whitewareweb.com/api.php). Make sure you are logged on to your Google/YouTube account and authorize access if prompted. Your video will now be uploaded!

YouTube Video Uploaded via OAuth API

Congratulations on uploading your first YouTube video using the OAuth API!

Below is a list of available YouTube categories along with their corresponding ID’s (not all categories will be available for your channel, but here’s a list for your convenience):

YouTube Category Names & ID’s

Category Name Category ID
Film & Animation 1
Autos & Vehicles 2
Music 10
Pets & Animals 15
Sports 17
Short Movies 18
Travel & Events 19
Gaming 20
Videoblogging 21
People & Blogs 22
Comedy 23
Entertainment 24
News & Politics 25
Howto & Style 26
Education 27
Science & Technology 28
Movies 30
Anime/Animation 31
Action/Adventure 32
Classics 33
Comedy 34
Documentary 35
Drama 36
Family 37
Foreign 38
Horror 39
Sci-Fi/Fantasy 40
Thriller 41
Shorts 42
Shows 43
Trailers 44

Have fun, and please share any interesting things you come across with us below.

Troubleshooting

The session state did not match

In case you get the message, The session state did not match, you may try putting the following code immediately before die(‘The session state did not match.’);:

var_dump($_SESSION['state']);
var_dump($_GET['state']);

Access Token Issues

If you are having issues with your access token, try visiting this link for more clues: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=[YOUR-ACCESS-TOKEN]

Caught Google service Exception 0

Are you getting this error?

PHP Warning: mkdir(): Permission denied in /../vendor/google/apiclient/src/Google/Cache/File.php on line 158
Caught Google service Exception 0 message is Could not create storage directory: /tmp/google-api-php-client/d4Stack trace is #0 /../vendor/google/apiclient/src/Google/Cache/File.php(146): Google_Cache_File->getCacheDir(”, true)

If so, try this code:
$client = new Google_Client();
$client->setCache(new Google_Cache_File('/path/to/shared/cache'));

Further reading: