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

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
Getting the web based generated token using the client library.
Getting the youtube upload permission from user for my application &
access_type=offline.
Access type offline gives refresh token in response. This token
will help to continue upload from backend server token when its
expires.
After getting the permission. It will redirect to URL with code.
Using the given code generate access_token
Save this token for future use.
Use the same token to push the video from your server to youtube
server
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.

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.
Becuase of the above limitation. You have use below Approach to work with this is-
Get the web based generated token using the client library.
Get the youtube upload permission from user for your application & access_type=offline.
Access type offline gives you refresh token in response. This token will help you to continue upload from backend server token when its expires.
After getting the permission. It will redirect to URL with code.
Using the given code generate access_token
Save this token for future use.
Use the same token to push the video from your server to youtube server
Refresh the token when it expires. And follow the step 3 - 5 again.
Currently this is the only way to upload the video on youtube.
Added the code on git repository nodejs-upload-youtube-video-using-google-api
For why its not possible? Check the below reference link & code:
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
From gadata Issues: Youtube v3 Google Service Account Access
From google blog spot:List of Google API supported using Service Account
Check below code to get access_token from server side
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);
});
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);
});
});
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' }
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' }
Screen shot attached for "How to get google key?"
Conclusion: Uploading a video without user permission is not possible.

Related

Node JS & Auth0 | Get profile

Hey developer friends,
I'm building a small alexa skill & use auth0 as the authentication system. Now I want to get the userinfo/profile of the user, because I need the userId. In the request from alexa is an an accessToken. With that token, I want to be able to get the information from auth0.
var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
domain: '[MY NAME].eu.auth0.com',
clientId: '[MY CLIENT ID]',
clientSecret: '[MY CLIENT SECRET]'
});
Then in the actual function:
const access_token = session.user.accessToken;
console.log("ACCESSTOKEN:", access_token)
auth0.getProfile(access_token, function (err, userInfo) {
if(err) {
console.log("failed to retrieve profile", err)
} else {
const userId = JSON.parse(userInfo)['sub'];
console.log(userId);
}
}
When I run the code, I get the error 401 Unauthorized from auth0, although I use the provided accessToken. The accessToken is something like this in the amazon request: "VDMj7VBJ0EaJ1XZhvVRUfPgYNtxviro"
Any suggestions on how to do that properly?
I initalized the auth module twice, fixed it & now it works fine!

Facebook accountkit gives error when exchanging tokens from nodeJS server

I have been integrating fb AccounKit with my ionic application (NodeJS server). Front-end part has been done and I'm able to send and receive OTPs and success status.
But while getting client token from authorization code, I keep getting ""Error verifying the token in the \'access_token\'"' error. I followed the same procedure mentioned in their official docs.
This is my code :
var me_endpoint_base_url = 'https://graph.accountkit.com/v1.0/me';
token_exchange_base_url='https://graph.accountkit.com/v1.0/access_token';
var params = {
grant_type: 'authorization_code',
code: request.body.code,
access_token: app_access_token
};
}
// exchange tokens
console.log(Querystring.stringify(params))
var token_exchange_url = token_exchange_base_url + '?' + Querystring.stringify(params);
Request.get({url: token_exchange_url, json: true}, function(err, resp, respBody) {
console.log(respBody);
var view = {
user_access_token: respBody.access_token,
expires_at: respBody.expires_at,
user_id: respBody.id,
};
var me_endpoint_url = me_endpoint_base_url + '?access_token=' + respBody.access_token;
Request.get({url: me_endpoint_url, json:true }, function(err, resp, respBody) {
console.log(respBody);
if (respBody.phone) {
view.method = "SMS"
view.identity = respBody.phone;
} else if (respBody.email) {
view.method = "Email"
view.identity = respBody.email.address;
}
});
});
Please help?
When making a sever-to-server call to exchange a code for a token, you need to supply your Account Kit App Secret in the access token you're sending.
So the access token should look like:
'AA|{app_id}|{app_secret}'
For ex.
var app_access_token = ['AA', app_id, app_secret].join('|');
You can find your app secret from the Account Kit dashboard. Go on "Account Kit" page under products section of your app on developers.facebook.com and click on the "Show" button next to the box for "Account Kit App Secret" to see your app secret.
Also remember that you should never include your app secret on any javascript code that runs on the client side. This secret is to be used only from your server-side node.js code and no one else should be able to see it

users.list returns 403 Error: Not Authorized to access this resource/api

I am trying to retrieve a list of users using the node.js googleapis library and a service account.
I followed this guide to 'Perform Google Apps Domain-Wide Delegation of Authority'. There are examples for Java and Python, but unfortunately not for node.js, which seems to work rather differently.
I tried following the quickstart and completed the first two steps, but then it uses a manual OAuth flow instead of a service account.
So I tried to follow the example here to authorize using a service account. That all seems to work until I send the request, then I get an error: Error: Not Authorized to access this resource/api with code: 403.
Here's my code:
var google = require('googleapis'),
GoogleAuth = require('google-auth-library'),
authFactory = new GoogleAuth(),
admin = google.admin('directory_v1')
authFactory.getApplicationDefault(function (err, authClient) {
console.log('GOT APPLICATION DEFAULT', authClient)
if (err) {
console.log('Authentication failed because of ', err);
return;
}
if (authClient.createScopedRequired && authClient.createScopedRequired()) {
console.log('SCOPE REQUIRED')
var scopes = ['https://www.googleapis.com/auth/admin.directory.user'];
authClient = authClient.createScoped(scopes);
}
var request = {
auth: authClient,
domain: 'mydomain.com'
};
console.log('request:', request)
admin.users.list(request, function (err, result) {
if (err) {
console.log('admin.users.list error', err);
} else {
console.log(result);
}
});
});
What have I missed please?
After several hours of experimenting I came to the conclusion that this particular API cannot be accessed with a service account. Although it is not explicitly stated in the docs anywhere that I could find, the quickstart seems to overcome this limitation by using an OAuth process and then storing in a file the tokens required to authorize future requests. If I'm wrong please add a better answer!
My solution is to use the quickstart project to generate those tokens and then add the credentials and tokens from the quickstart to my project and use them whenever my server starts, something like:
let tokens = require('./credentials/tokens.json'),
credentials = require('./credentials/oauth_credentials.json'),
clientSecret = credentials.installed.client_secret,
clientId = credentials.installed.client_id,
redirectUrl = credentials.installed.redirect_uris[0],
google = require('googleapis'),
GoogleAuth = require('google-auth-library'),
authFactory = new GoogleAuth(),
admin = google.admin('directory_v1'),
oauth2Client = new authFactory.OAuth2(clientId, clientSecret, redirectUrl);
oauth2Client.credentials = tokens;
let request = {
auth: oauth2Client,
domain: 'coachaxis.com'
};
console.log('request:', request)
admin.users.list(request, function (err, result) {
if (err) {
console.log('admin.users.list error', err);
} else {
console.log(result);
}
});
It's not elegant but it works.

Google Play Android Developer API 401 Insufficient permissions

I'm using Google Play Android Developer API to server to server check subscription status of our users' subscriptions but after successful authorization and asking for an existing subscription I get the 401 response with the following message 'The current user has insufficient permissions to perform the requsted operation'.
Visiting https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=XXXXXX I can see that I do have the requested scope (https://www.googleapis.com/auth/androidpublisher) but I still get the same response everytime.
Did anyone else have the same problem?
Edit: I've seen what the Explore API app does, it adds the key in the query string of a request but I don't have that value. In the console I've created a Service Account Client Id which has a client id, email address and a private key but there is no API key which apparently Explore API uses.
Edit no. 2: I've added the service account generated email both to Google Play Developer Console and Google Wallet console but I still have no acces. I'm using nodejs and the google-oauth-jwt because there is not google provided lib for nodejs.
Here is the code I'm using to make a request:
var request = require('google-oauth-jwt').requestWithJWT();
function makeReq() {
request({
url: 'https://www.googleapis.com/androidpublisher/v1.1/applications/{packageName}/subscriptions/{subscriptionId}/purchases/{purchaseToken}',
jwt: {
// use the email address of the service account, as seen in the API console
email: 'blahblahtrutjtrutj#developer.gserviceaccount.com',
// use the PEM file we generated from the downloaded key
keyFile: 'purchases-test.pem',
// specify the scopes you wish to access
scopes: ['https://www.googleapis.com/auth/androidpublisher']
}
}, function (err, res, body) {
if (err) {
console.log(err);
} else {
console.log("BODY IS ------------------------------------------");
console.log(JSON.parse(body));
}
});
}
If your app is only released in a closed alpha track, you'll also have to add your service account's email address (client_email) to the License Testers at Settings -> Account detail in the Play Console.
There is an email address associated with your service account.
This needs to have appropriate permissions in both the dev console AND the Play store. Make sure to add the service address to the Play store.
The way I approached it was to use
var googleAuth = require('google-oauth-jwt'),
authObject = {
email: 'blahblahtrutjtrutj#developer.gserviceaccount.com',
keyFile: 'purchases-test.pem',
scopes: ['https://www.googleapis.com/auth/androidpublisher']
};
googleAuth.authenticate(authObject, function (err, token) {
next(err, token);
});
I store the token in redis for an hour and use that token to make my request to the store:
var opts = {
url : verifyUrl + payload.packageName + '/inapp/' + payload.productId + '/purchases/' + payload.token,
headers: {
authorization : 'Bearer ' + token
}
};
request.get(opts, function (error, response, body) {
next(error, response, body);
});

Accessing google analytics through nodejs

I'm using nodejs, and I would like to display some data from google analytics.
On google API explorer, I've find this url to get my data:
https://www.googleapis.com/analytics/v3/data/ga?ids=ga%XXXXX&start-date=2013-08-17&end-date=2013-09-15&metrics=ga%3Avisits&key={YOUR_API_KEY}
However, if I access this url I get:
{"error":{"errors":[{"domain":"global","reason":"required","message":"Login Required","locationType":"header","location":"Authorization"}],"code":401,"message":"Login Required"}}
How can I pass my login through the url and then access my data ?
Thanks!
From the Google API console, you need to activate the Analytics API, and finally setup a Service Account, you'll then download a *.p12 file.
From this *.p12 file, you need to convert it to a *.pem file, to do that, run the following:
openssl pkcs12 -in XXXXX.p12 -nocerts -nodes -out XXXXX.pem
You'll be asked a password, it should be notasecret
Now you got the *.pem file you need, and the account email is the one displayed in the google api console, as EMAIL ADDRESS.
Don't forget to add this address to your analytics account (see: Analytics Google API Error 403: "User does not have any Google Analytics Account")
You should be good to go with the following snippet:
var googleapis = require('googleapis'),
JWT = googleapis.auth.JWT,
analytics = googleapis.analytics('v3');
var SERVICE_ACCOUNT_EMAIL = 'XXXXXXXXXX#developer.gserviceaccount.com';
var SERVICE_ACCOUNT_KEY_FILE = __dirname + '/key.pem';
var authClient = new JWT(
SERVICE_ACCOUNT_EMAIL,
SERVICE_ACCOUNT_KEY_FILE,
null,
['https://www.googleapis.com/auth/analytics.readonly']
);
authClient.authorize(function(err, tokens) {
if (err) {
console.log(err);
return;
}
analytics.data.ga.get({
auth: authClient,
'ids': 'ga:XXXXXXXX',
'start-date': '2015-01-19',
'end-date': '2015-01-19',
'metrics': 'ga:visits'
}, function(err, result) {
console.log(err);
console.log(result);
});
});
Are you setting Content-Type to application/x-www-form-urlencoded?
If you're still stuck, it's worth noting that Google has released a nodejs client library (alpha) here: https://github.com/google/google-api-nodejs-client
#xavier.seignard I follow your snippet but with modifications because I'm using a json file instead of p12 (code below).
But I have a doubt, I'm developing a restful backend in nodejs.
In this case, isn't it necessary to put the ga.get function inside the app.use() to obtain analytics information for every request that is made?
var key = require('filename.json');
var authClient = new JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/analytics.readonly']);
Below I have mentioned step by step process for Accessing google analytics through nodejs:
For more details : How To Use Google Analytics Reporting API With Nodejs
Install googleapis package
npm i googleapis
Import
const { google } = require('googleapis')
This is sample scripts for getting total views in last month:
const { google } = require("googleapis");
const scopes = "https://www.googleapis.com/auth/analytics.readonly";
const jwt = new google.auth.JWT(
process.env.CLIENT_EMAIL,
null,
process.env.PRIVATE_KEY.replace(/\\n/g, "\n"),
scopes
);
const view_id = "Your_View_ID";
async function getViews(){
try {
await jwt.authorize();
const response = await google.analytics("v3").data.ga.get({
auth: jwt,
ids: "ga:" + view_id,
"start-date": "30daysAgo",
"end-date": "today",
metrics: "ga:pageviews",
});
console.log(response);
} catch (err) {
console.log(err);
}
};`

Resources