how do I auto authenticate google javascript api ? REST api - javascript

I am using php. and want to use some javascript api function in my application. so can any one know that how can I auto authenticate this process:
<!--Add a button for the user to click to initiate auth sequence -->
<button id="authorize-button" style="visibility: hidden">Authorize</button>
<script type="text/javascript">
var clientId = '837050751313';
var apiKey = 'AIzaSyAdjHPT5Pb7Nu56WJ_nlrMGOAgUAtKjiPM';
var scopes = 'https://www.googleapis.com/auth/plus.me';
function handleClientLoad() {
// Step 2: Reference the API key
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick(event) {
// Step 3: get authorization to use private data
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
return false;
}
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
// Step 4: Load the Google+ API
gapi.client.load('plus', 'v1').then(function() {
// Step 5: Assemble the API request
var request = gapi.client.plus.people.get({
'userId': 'me'
});
// Step 6: Execute the API request
request.then(function(resp) {
var heading = document.createElement('h4');
var image = document.createElement('img');
image.src = resp.result.image.url;
heading.appendChild(image);
heading.appendChild(document.createTextNode(resp.result.displayName));
document.getElementById('content').appendChild(heading);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
});
}
</script>
// Step 1: Load JavaScript client library
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
I have .json and also .p12 file for authenticate but I only want to direct access to api function instead of redirecting to google for permission access.

When using the Google+ API or other API that accesses user-specific data (e.g. Gmail, Calendar), you need to either use an OAuth client and ask the user for permission to access their data (i.e. the "redirect to google for permission access"), or use a service account.
A service account is a robot account that is used in place of a real user. If you decide to use a service account, you'll need to use the JSON or P12 key as you mentioned. Using a service account from JavaScript code requires a lot of work and is generally insecure since you would be making your service account key accessible to everyone. If you're going to use a service account, you should call the API from the server using a Google API Client Library.

Related

Is it safe to have visible Google Drive API keys in Javascript?

I am using Google drive API to download file from Google drive. I am using Javascript for that. Is it safe to have visible API keys in JS or I should use Node.js or something else? As you can see on the top of code, there are many keys (developer key, client id and app id). Is there any vulnerable in my code?
Here is my code:
var developerKey = '[key]';
var clientId = "[key]"
var appId = "[key]";
var scope = ['https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive'];
var pickerApiLoaded = false;
var driveLoaded = false;
var oauthToken;
// Use the Google API Loader script to load the google.picker script.
function loadPicker() {
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
gapi.load('client', function () {
gapi.client.load('drive', 'v2', function () {
driveLoaded = true;
});
});
}
function onAuthApiLoad() {
window.gapi.auth.authorize(
{
'client_id': clientId,
'scope': scope,
'immediate': false
},
handleAuthResult);
}
function onPickerApiLoad() {
pickerApiLoaded = true;
createPicker();
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
}
}
// Create and render a Picker object for searching images.
function createPicker() {
if (pickerApiLoaded && oauthToken) {
var view = new google.picker.View(google.picker.ViewId.DOCS);
view.setMimeTypes("application/sla,application/vnd.ms-pki.stl,application/x-navistyle");
var picker = new google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.setAppId(appId)
.setOAuthToken(oauthToken)
.addView(view)
.addView(new google.picker.DocsUploadView())
.setDeveloperKey(developerKey)
.setCallback(pickerCallback)
.build();
picker.setVisible(true);
}
}
// A simple callback implementation.
function pickerCallback(data) {
if (data.action == google.picker.Action.PICKED) {
var fileId = data.docs[0].id;
downloadFile(fileId, data.docs[0].name);
}
}
function downloadFile(fileId, fileName)
{
var request = gapi.client.drive.files.get({
fileId:fileId,
alt:"media"
}).then(function(resp){
$.post("PHP/save_file.php", {Type: "stl", Filename: fileName, Data: resp.body}, function(response) {
if (response == "OK")
{
}
});
});
}
function showPickerDialog(){
loadPicker()
}
When you created your app on Google Developer console you created a web application. When you created it you added a javascript origin. As long as you set this javascript origin to the location of your webserver that the application is running on then there is no way anyone can use your client id. If you have left it set to localhost then yes there is a risk that someone could hijack your token and use it.
As for the api key you should lock that down to a specific domain, however api keys only give you access to read public data. The amount of public data in Google Drive but someone could abuse your api key if you dont lock it down.

Cannot read property 'init' of undefined gapi.client

I am trying to integrate Google Calendar API with Js inside an application. I tried to follow Google Quickstart. If I paste the example code in an HTML doc, change the clientID and the API key, I get the error attached when I open the file in Chrome.
Also, with console.log(gapi.client) I get back null.
The first block of code is where gapi functions are called (calendar_model.js).
The second block is where I link the api script to the document (I need to do that by js, in a file called dependency.js).
The third block is my index.js, from where I call the function in dependency.js.
console.log("first");
// Client ID and API key from the Developer Console
var CLIENT_ID = 'xxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
var API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = "https://www.googleapis.com/auth/calendar.readonly";
var authorizeButton;
var signoutButton;
/**
* On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
console.log("gapi type: " + typeof gapi + '\n');
console.log("gapi client type: " + typeof gapi.client + '\n');
gapi.load('client:auth2', initClient);
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
function initClient()
{
console.log("initClient callback start");
gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES
}).then(function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
console.log(gapi);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
}, function(error) {
appendPre(JSON.stringify(error, null, 2));
});
}
window.testMicroAppDependency = {
calendarInit: function(){
var calendar_root = document.getElementById("gcalendar-root");
//create authorize button
var x = document.createElement("button");
x.setAttribute("id", "authorize_button");
//x.style = "display: none";
calendar_root.appendChild(x);
//create signout button
x = document.createElement("button");
x.setAttribute("id", "signout_button");
//x.style = "display: none";
calendar_root.appendChild(x);
authorizeButton = document.getElementById('authorize_button');
signoutButton = document.getElementById('signout_button');
x = document.createElement("script");
x.src = "https://apis.google.com/js/api.js";
x.async = true;
x.defer = true;
x.setAttribute("onload", "handleClientLoad()");
x.setAttribute("onreadystatechange", "if (this.readyState === 'complete') this.onload()");
calendar_root.appendChild(x);
}
}
registry.add("microapp", "googlecalendar", {
init: function (parentNode, options) {
this._waitForDependency(function (error, dependency) {
if (error) {
console.error("Unable to start Google Calendar MicroApp: " + error);
} else {
var content = document.createElement("div");
content.setAttribute("id", "gcalendar-root");
parentNode.appendChild(content);
dependency.calendarInit();
}
});
},
_waitForDependency: function(callback) {
var timeout = 5000;
var startTime = new Date().getTime();
var interval = setInterval(function() {
if (window.hasOwnProperty("testMicroAppDependency")) {
clearInterval(interval);
callback(null, window.testMicroAppDependency);
}
if (new Date().getTime() - startTime > timeout) {
clearInterval(interval);
callback("Loading of HelloWorld MicroApp scripts timed out.", null);
}
console.log("... (waiting for testMicroAppDependency)");
}, 100);
}
});
Here is the console where I log the type of gapi and of gapi.client. gapi is an object, so the library is loaded, but gapi.client is undefined.
I am pretty a newbie in web dev, maybe it's a silly issue or I didn't comprehend something about Google API, but I can't get resolve it.
Any help is appreciated :)
The main issue you are having is you are calling initClient function as an explicit function here:
gapi.load('client:auth2', initClient())
you have to pass it as an implicit function because gapi.load will use it as a callback (I recommend you to check more about them). Therefore, it must be passed like this:
gapi.load('client:auth2', initClient)
Notice the subtle, but really important difference between the parenthesis in initClient() and initClient.
Also, you have these variables in the air without assigning them values for what I could see:
var authorizeButton;
var signoutButton;
They should be assigned the button elements to eventually handle them in your code:
var authorizeButton = document.getElementById('authorize_button');
var signoutButton = document.getElementById('signout_button');

Ouath2 in Google Apps Script

I've followed the guide on https://github.com/gsuitedevs/apps-script-oauth2 for setting up the Oauth2 token for a google services very closely but i'm still not able to get the access token to work.
The error I'm receiving is Access not granted or expired. (line 454, file "Service", project "OAuth2")
Note* My project has already been whitelisted for the GMB API library and I have enabled it in the API console console. I retrieved a ClientID and ClientSecret from my project aswell.
//Oauth 2 Flow Start
function getGmbService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
return OAuth2.createService('gmb')
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId('...')
.setClientSecret('...')
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
.setCache(CacheService.getUserCache())
// Set the scopes to request (space-separated for Google services).
.setScope('https://www.googleapis.com/auth/business.manage')
// Below are Google-specific OAuth2 parameters.
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
.setParam('login_hint', Session.getActiveUser().getEmail())
// Requests offline access.
.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
.setParam('approval_prompt', 'force');
}
function showSidebar() {
var gmbService = getGmbService();
if (!gmbService.hasAccess()) {
var authorizationUrl = gmbService.getAuthorizationUrl();
var template = HtmlService.createTemplate(
'Authorize. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
var page = template.evaluate();
DocumentApp.getUi().showSidebar(page);
} else {
Logger.log("No Access")
}
}
function authCallback(request) {
var gmbService = getGmbService();
var isAuthorized = gmbService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
//Oauth2 Flow Finish
function testRequest() {
var gmbService = getGmbService();
var payload = {
"pageSize": 5
}
var options = {
"headers": {
"Authorization": 'Bearer ' + gmbService.getAccessToken()
},
"method": 'GET',
"payload": payload,
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch("https://mybusiness.googleapis.com/v4/accounts",options)
Logger.log(response);
}

Multiple user Auth Simultaneously for Gmail API

I want to show the total email count in my multiple accounts on a single page. Currently I auth one by one for all email account and then store the email count in array.
But, I need to refresh the count after 10s and I can't auth every 10s. So is there any method where I can keep multiple Gmail accounts logged in and fetch email count periodically.
This Method gets email count:
function listLabels() {
gapi.client.gmail.users.labels.get({
'userId': 'me',
'id': 'INBOX'
}).then(function(response) {
ct.push(response.result.messagesTotal)
});
}
This is used for auth:
var ct = [];
// Client ID and API key from the Developer Console
var CLIENT_ID = '<CLIENT ID>';
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = 'https://www.googleapis.com/auth/gmail.readonly';
var authorizeButton = document.getElementById('authorize_button');
var signoutButton = document.getElementById('signout_button');
/**
* On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
function initClient() {
gapi.client.init({
discoveryDocs: DISCOVERY_DOCS,
clientId: CLIENT_ID,
scope: SCOPES
}).then(function() {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
});
}
/**
* Called when the signed in status changes, to update the UI
* appropriately. After a sign-in, the API is called.
*/
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
authorizeButton.style.display = 'none';
signoutButton.style.display = 'block';
listLabels();
} else {
authorizeButton.style.display = 'block';
signoutButton.style.display = 'none';
}
}
/**
* Sign in the user upon button click.
*/
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
}
/**
* Sign out the user upon button click.
*/
function handleSignoutClick(event) {
gapi.auth2.getAuthInstance().signOut();
}

OAuth1 authenticated calls on Khan Academy's API using Google App Script

I'm pretty new to coding. I'm using Google App Script, which is supposed to be javascript based and a library to manage OAuth1 api authentication. I'm trying to authenticate with the Khan Academy. This script which I got from the google apps site works to a point. The function 'listTweets' takes me to the 'else' branch and logs the url to take me to Khan Academy to grant the script permission to make the call. I accept and am supposed to rerun the function and end up in the 'then' branch of the 'if-then-else' statement. I just keep getting sent down the else. Does anyone know what gives? Thanks in advance for any help.
var CONSUMER_KEY = 'my key';
var CONSUMER_SECRET = 'my secret';
var PROJECT_KEY = 'my google project key';
function listTweets() {
var service = getTwitterService();
if (service.hasAccess()) {
var response = service.fetch('https://www.khanacademy.org//api/v1/user/exercises');
var tweets = JSON.parse(response.getContentText());
Logger.log(tweets);
} else {
var authorizationUrl = service.authorize();
Logger.log('Please visit the following URL and then re-run the script: ' + authorizationUrl);
}
}
function getTwitterService() {
var service = OAuth1.createService('twitter');
service.setAccessTokenUrl('https://www.khanacademy.org/api/auth2/access_token')
service.setRequestTokenUrl('https://www.khanacademy.org/api/auth2/request_token')
service.setAuthorizationUrl('https://www.khanacademy.org/api/auth2/authorize')
service.setConsumerKey(CONSUMER_KEY);
service.setConsumerSecret(CONSUMER_SECRET);
service.setProjectKey(PROJECT_KEY);
service.setCallbackFunction('authCallback');
service.setPropertyStore(PropertiesService.getScriptProperties());
service.setOAuthVersion('1.0');
return service;
}
function authCallback(request) {
var service = getTwitterService();
var isAuthorized = service.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this page.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this page');
}
}
I'm not familiar with this particular API, but reading through their documentation, and looking the PHP example, it appears that they are expecting the OAuth parameters to be passed in the URL rather than the Authorization Header.
By default, the OAuth services use the Authorization header, but this can be over-ridden with service.setParamLocation('uri-query').
I was able to reproduce and track down your problem. Funny enough, it ends up being a single-character fix (after the setParamLocation fix already mentioned): you just need to use OAuth version "1.0a" instead of "1.0". OAuth version 1.0a changed some of the details of how the OAuth callback works to fix a security issue, and I guess this OAuth library only includes the callback URL in the request_token step when using OAuth 1.0a. The KA API always uses the callback specified in the request_token step, so the previous version of the app script was never running the callback.
Here's some code that works for me:
var CONSUMER_KEY = 'FILL ME IN';
var CONSUMER_SECRET = 'FILL ME IN';
var PROJECT_KEY = 'FILL ME IN';
function listExercises() {
var service = getKhanAcademyService();
if (service.hasAccess()) {
var response = service.fetch('https://www.khanacademy.org/api/v1/user/exercises');
var exercises = JSON.parse(response.getContentText());
Logger.log(exercises);
} else {
var authorizationUrl = service.authorize();
Logger.log('Please visit the following URL and then re-run the script: ' + authorizationUrl);
}
}
function getKhanAcademyService() {
var service = OAuth1.createService('khanAcademy');
service.setAccessTokenUrl('https://www.khanacademy.org/api/auth2/access_token')
service.setRequestTokenUrl('https://www.khanacademy.org/api/auth2/request_token')
service.setAuthorizationUrl('https://www.khanacademy.org/api/auth2/authorize')
service.setConsumerKey(CONSUMER_KEY);
service.setConsumerSecret(CONSUMER_SECRET);
service.setProjectKey(PROJECT_KEY);
service.setCallbackFunction('authCallback');
service.setPropertyStore(PropertiesService.getScriptProperties());
service.setOAuthVersion('1.0a');
service.setParamLocation('uri-query');
return service;
}
function authCallback(request) {
var service = getKhanAcademyService();
var isAuthorized = service.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this page');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this page');
}
}

Categories

Resources