Google OAuth2 verification hangs - google-chrome-extension

I am trying to write a Google Chrome extension that will replace the new tab page and can connect to a users Google Calendar to show upcoming events. I am having trouble getting the extension to properly authorize access with OAuth.
I am testing the following code to authorize the user:
func.js
// initialize google api
gapi.client.setApiKey('MY API KEY');
gapi.client.load('calendar', 'v3', function() {
console.log('calendar api loaded')
});
// OAuth2 verification
function auth() {
var config = {
'client_id': 'MY CLIENT ID',
'scope': 'https://www.googleapis.com/auth/calendar'
};
gapi.auth.authorize(config, function() {
console.log('login complete');
console.log(gapi.auth.getToken());
});
}
manifest.json
{
// ...
"oauth2": {
"client_id": "MY CLIENT_ID",
"scopes": [
"https://www.googleapis.com/auth/calendar"
]
},
// ...
}
The Google API is initialized properly and the callback function is called. Before I added the "oauth2" parameter to manifest.json, I received an error from Google, but now when auth() is called the authentication popup window appears, but it just stays blank and says 'connecting' and nothing ever shows. Am I doing OAuth verification correctly? What is causing this hang?

Turns out I needed to add 'immediate': true inside var config

Related

How to know authenticated email of an user who authenticated with his google account for my app

I am integrating google authentication for my app for creating calender events.
const {google} = require('googleapis');
const SCOPES = ['https://www.googleapis.com/auth/calendar','https://www.googleapis.com/auth/userinfo.email']
I have used the above scopes in authentication and generated the url and sent to the client. Authentication got success and i am able to receive code and generating token.
But with the code, I need the authenticated user's email, whoever signed in. Is there any way/example to know how to get user's email?. I searched in google for finding solution. But i didn't get that. Help me to know about this.
After you have received the token, you need to make a HTTP request to the userinfo endpoint using that token to get the required user info.
You can get the url for that endpoint from the discovery document which can be found at https://accounts.google.com/.well-known/openid-configuration.
The current url to get user info is https://openidconnect.googleapis.com/v1/userinfo.
If you do a calendar get on the users primary calendar. All users have a primary calendar
request
GET https://www.googleapis.com/calendar/v3/calendars/primary
response
{
"kind": "calendar#calendar",
"etag": "\"JWPyaEfg9X1jMhlHCcI4tl2h6uo/AxePbI13h8-KuIOLek\"",
"id": "xxxx#gmail.com",
"summary": "xxx#gmail.com",
"timeZone": "Europe/Copenhagen",
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"eventHangout"
]
}
}
Both Id and summary will be the users email address. By doing it this way you will not need to request the https://www.googleapis.com/auth/userinfo.email scope
Node guesss
Note: I am not a node.js developer this is a wild guess you will have to work this out
function listEvents(auth) {
const calendar = google.calendar({version: 'v3', auth});
calendar.about.get({
calendarId: 'primary'
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const results = res;
if (results ) {
console.log(results.id);
} else {
console.log('No upcoming events found.');
}
});

how to "add participants" for private youtube video using youtube api

I am trying to stream video using the Youtube api.
I want to stream video in private mode.
Here is my code for the same
`const {google} = require('googleapis');
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2(
//CLIENT_ID
//CLIENT SCRETE
// YOUR_REDIRECT_URL
);
oauth2Client.setCredentials({
access_token: //access token,
refresh_token: //refresh token
});
oauth2Client.refreshAccessToken((err, tokens) => {
});
const youtube = google.youtube({
version: 'v3',
auth : oauth2Client
});
broadcastParams = {
"part": "snippet,status,contentDetails",
"resource": {
"snippet": {
"title": "into the starry sky..",
//"scheduledStartTime": "2018-03-04T20:50:00.000Z",
// "scheduledEndTime": "2018-03-03T18:05:00.000Z",
},
"status": {
"privacyStatus": "private",
},
"contentDetails": {
"monitorStream": {
"enableMonitorStream": true,
}
},
"cdn": ''
}
};
// TODO watch the auth parameters in broadcasting in the console testing
youtube.broadcast.insert(broadcastParams, function (err, broadcast) {
if (err) {
return console.log('Error creating broadcast: ', err);
}
console.log('Broadcast = ' + broadcast.valueOf());
});`
But I want to add participant's email address so as to make them see the private video which only the added person could see.
If there is any way to do this please help me out.
Thanks in advance
[1]: http://developers.google.com/youtube/v3/
After some research I came to know that YouTube's private videos require that the viewer have a YouTube account, be signed into that account and have that account added to the video's access list. Its also limited to 50 people only.
And also need to change the contentDetails parameter from monitorStream to broadcast stream. But need to explicitly invite people and there is no other way to invite people using API.
So for most of the case it's preferred to use unlisted for the streaming which means person with the link can view the video and It can be embedded in website too.

Refresh token for Google APIs to keep user logged in

I am developing an App on Actions on Google that uses Google Calendar. At the start of a user's first interaction, they are prompted to link their Google account for access to the calendar. But then for nearly every future interaction, the user has to authenticate again.
My code to get the access token from the user data is below. I'm not sure if there's a way to get the refresh token to add to the credentials. I've seen you should include "access_type": "offline" in the request in other answers, but I'm not sure where I'd put it in my code. Any help would be greatly appreciated!
const googleAuth = require('google-auth-library');
function getAuth(app) {
var accessToken = app.getUser().accessToken;
var clientId = CLIENT_ID;
var clientSecret = CLIENT_SECRET;
var redirectUrl = 'https://oauth-redirect.googleusercontent.com/r/my_app_name';
var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
var token = {
"access_token": accessToken,
"refresh_token": "",
"access_type": "offline", //Not sure if these attributes should be here
"approval_prompt": "force",
"immediate": true,
"token_type": "Bearer"
};
oauth2Client.credentials = token;
return oauth2Client;
}
calendar.freebusy.query ({
auth: getAuth(app), //need a Google OAuth client here for API request
headers: { "content-type" : "application/json" },
resource:{
items: [
{
id: "primary"
}
],
timeMin: startDate.format(),
timeMax: endDate.format(),
timeZone: timeZoneId
}, function(err, response) {
console.log('Success!');
}
});
Not sure if this helps, but on the very first interaction a user has to select an account and agree to the calendar permission, but on subsequent interactions they just have to tap "link account to Google" and it automatically authenticates them.
EDIT:
This is a screenshot of the prompt I get on every new interaction with the app. It was my understanding that account linking is only done on the very first interaction with the app, then the accounts are linked for good and the user need not be prompted again. I am not receiving any errors, I was just wondering if and how I can modify my current code to not prompt the user to link their account on every single interaction.

Video upload using youtube/google API directly from server using 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.

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);
});

Resources