Video upload using youtube/google API directly from server using node.js?

sathishkumar picture sathishkumar · Sep 12, 2014 · Viewed 7.4k times · Source

I am trying to upload videos from server without any manual authentication by user in the client side . I tried the below code snippet for video upload but it authenticates the user in the browser and asks for the acceptance of the app.

var ResumableUpload = require('node-youtube-resumable-upload');
var googleauth = require('google-auth-cli');
var google = require('googleapis');

var getTokens = function(callback) {
  googleauth({
      access_type: 'offline',
      scope: 'https://www.googleapis.com/auth/youtube.upload' //can do just 'youtube', but 'youtube.upload' is more restrictive
  },
  {     client_id: CLIENT_ID, //replace with your client_id and _secret
      client_secret: CLIENT_SECRET,
      port: 3000
  },
  function(err, authClient, tokens) {
    console.log(tokens);
    callback(tokens);
  });
};

getTokens(function(result) {
  tokens = result;
  upload();
});



var upload = function() {
      var metadata = {snippet: { title: 'title', description: 'Uploaded with ResumableUpload' },
          status: { privacyStatus: 'public' }};
      var resumableUpload = new ResumableUpload(); //create new ResumableUpload
      resumableUpload.tokens = tokens;
      resumableUpload.filepath = 'youtube/test4.mp4';
      resumableUpload.metadata = metadata;
      resumableUpload.monitor = true;
    resumableUpload.eventEmitter.on('progress', function(progress) {
        console.log(progress);
    });
      resumableUpload.initUpload(function(result) {
        console.log(result);
        return;
      });
    }

But for my app it should directly upload the video to youtube from the server. For that I need the access token and refresh token I tried lot to get the access token directly but I couldn't able to get it.

So any help or idea to how to make the video upload directly from server to a channel account. I searched lot in google for a node module to do that but I couldn't able to find it.

I have been using this approach to upload video

  1. Getting the web based generated token using the client library.
  2. Getting the youtube upload permission from user for my application & access_type=offline.
  3. Access type offline gives refresh token in response. This token will help to continue upload from backend server token when its expires.
  4. After getting the permission. It will redirect to URL with code.
  5. Using the given code generate access_token
  6. Save this token for future use.
  7. Use the same token to push the video from your server to youtube server
  8. Refresh the token when it expires.

But is there any way to implement this approach without getting the youtube upload permission from user for my application.

Answer

rajesh ujade picture rajesh ujade · Sep 16, 2014

You can do server side authetication using google API(JWT) with "Service Account". But direct upload from your server to youtube server without user permission is not possible. For uploading the video google needs OAuth2.0 authentication. It will give you error unAuthorized(401)- youtubeSignupRequired with "Service Account" using JWT authentication. youtubeSignupRequired

Becuase of the above limitation. You have use below Approach to work with this is-

  1. Get the web based generated token using the client library.
  2. Get the youtube upload permission from user for your application & access_type=offline.
  3. Access type offline gives you refresh token in response. This token will help you to continue upload from backend server token when its expires.
  4. After getting the permission. It will redirect to URL with code.
  5. Using the given code generate access_token
  6. Save this token for future use.
  7. Use the same token to push the video from your server to youtube server
  8. Refresh the token when it expires. And follow the step 3 - 5 again.
  9. Currently this is the only way to upload the video on youtube.
  10. Added the code on git repository nodejs-upload-youtube-video-using-google-api

For why its not possible? Check the below reference link & code:

  1. From google API Doc: This error is commonly seen if you try to use the OAuth 2.0 Service Account flow. YouTube does not support Service Accounts, and if you attempt to authenticate using a Service Account, you will get this error. You can check all the error code & its detail using link: YouTube Data API - Errors
  2. From gadata Issues: Youtube v3 Google Service Account Access
  3. From google blog spot:List of Google API supported using Service Account
  4. Check below code to get access_token from server side
  5. You can check it yourself using below steps & code:

    • Go to Google Developer Console
    • Create Project
    • To Get Google+ API Access go to: APIs & Auth->APIs ->enable YouTube Data API v3
    • To Enable Service Account go to: APIs & Auth->Credentials->Create new Client ID->Click on Service Account->Create Client Id
    • Save the secret file on your system & keep it secure.
    • Create the secret key using below command & file you have downloaded:

openssl pkcs12 -in /home/rajesh/Downloads/Yourkeyfile.p12 -out youtube.pem -nodes

- Enter password: ***notasecret***

6. You can authorize & access api from server side as below:

    var google = require('googleapis');
    var authClient = new google.auth.JWT(
            'Service account client email address', #You will get "Email address" in developer console for Service Account:
            'youtube.pem', #path to pem file which we create using step 6
            null,
            ['https://www.googleapis.com/auth/youtube.upload'],
            null
    );
    authClient.authorize(function(err, tokens) {
       if (err) {
               console.log(err);
               return;
       }
       console.log(tokens);
    });
  1. Get youtube video list using Service Account(working):

         var google = require('googleapis');
         var youtube = google.youtube('v3');
         var authClient = new google.auth.JWT(
              'Service account client email address', #You will get "Email address" in developer console for Service Account:
              'youtube.pem',
              null,
           ['https://www.googleapis.com/auth/youtube','https://www.googleapis.com/auth/youtube.upload'],
           null
         );
        authClient.authorize(function(err, tokens) {
            if (err) {
               console.log(err);
               return;
        }
        youtube.videos.list({auth:authClient,part:'snippet',chart:'mostPopular'}, function(err, resp) {
           console.log(resp);
           console.log(err);
         });
        });
    
  2. Insert youtube video using Service Account and googleapis module:

         var google = require('googleapis');
         var youtube = google.youtube('v3');
         var authClient = new google.auth.JWT(
              'Service account client email address', #You will get "Email address" in developer console for Service Account:
              'youtube.pem',
              null,
           ['https://www.googleapis.com/auth/youtube','https://www.googleapis.com/auth/youtube.upload'],
           null
         );
        authClient.authorize(function(err, tokens) {
            if (err) {
               console.log(err);
               return;
        }
          youtube.videos.insert({auth:authClient,part:'snippet,status,contentDetails'},function(err,resp)
           console.log(resp);
           console.log(err);
         });
        });
    

Insert/Upload API Returned below Error:

{ errors: 
   [ { domain: 'youtube.header',
       reason: 'youtubeSignupRequired',
       message: 'Unauthorized',
       locationType: 'header',
       location: 'Authorization' } ],
  code: 401,
  message: 'Unauthorized' }
  1. Insert youtube video using Service Account and ResumableUpload module:

         var google = require('googleapis');
         var ResumableUpload = require('node-youtube-resumable-upload');
         var authClient = new google.auth.JWT(
              'Service account client email address', #You will get "Email address" in developer console for Service Account:
              'youtube.pem',
              null,
           ['https://www.googleapis.com/auth/youtube','https://www.googleapis.com/auth/youtube.upload'],
           null
         );
        authClient.authorize(function(err, tokens) {
            if (err) {
               console.log(err);
               return;
        }
          var metadata = {snippet: { title: 'title', description: 'Uploaded with ResumableUpload' },status: { privacyStatus: 'private' }};
          var resumableUpload = new ResumableUpload(); //create new ResumableUpload
          resumableUpload.tokens = tokens;
          resumableUpload.filepath = 'youtube.3gp';
          resumableUpload.metadata = metadata;
          resumableUpload.monitor = true;
          resumableUpload.eventEmitter.on('progress', function(progress) {
               console.log(progress);
          });
          resumableUpload.initUpload(function(result) {
               console.log(result);
               return;
          });
    
        });
    

Insert/Upload API Returned below Error:

   { 'www-authenticate': 'Bearer realm="https://accounts.google.com/AuthSubRequest", error=invalid_token',
  'content-type': 'application/json; charset=UTF-8',
  'content-length': '255',
  date: 'Tue, 16 Sep 2014 10:21:53 GMT',
  server: 'UploadServer ("Built on Aug 18 2014 11:58:36 (1408388316)")',
  'alternate-protocol': '443:quic,p=0.002' }
  1. Screen shot attached for "How to get google key?" Create Client Id Download Application key & Password Client Email id used to call using backend

Conclusion: Uploading a video without user permission is not possible.