Google Drive API authentication, JavaScript - javascript

I am running on a virtual host (as well as a Python SimpleHTTPServer) and I have been following Google's instructions, but I can't get the Google drive authorization to pop up on page refresh.
https://developers.google.com/drive/web/auth/web-client
Ive placed the first block of code in my index.html file, and Ive placed the following 2 snippets in <script> tags within <body>. I filled in the CLIENT_ID with the ID I created in the Google developer console...what am I missing?
<html>
<head>
<script type="text/javascript">
var CLIENT_ID = '1052173400541-355uhjrflurk7fmlon0r5umnn12i9ag3.apps.googleusercontent.com';
var SCOPES = [
'https://www.googleapis.com/auth/drive.file',
'email',
'profile',
// Add other scopes needed by your application.
];
/**
* Called when the client library is loaded.
*/
function handleClientLoad() {
checkAuth();
}
/**
* Check if the current user has authorized the application.
*/
function checkAuth() {
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': true},
handleAuthResult);
}
/**
* Called when authorization server replies.
*
* #param {Object} authResult Authorization result.
*/
function handleAuthResult(authResult) {
if (authResult) {
// Access token has been successfully retrieved, requests can be sent to the API
} else {
// No access token could be retrieved, force the authorization flow.
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': false},
handleAuthResult);
}
}
</script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
</head>
<body>
<h1>welcome to google_drive.local</h1>
<script type='text/javascript'>
/**
* Load the Drive API client.
* #param {Function} callback Function to call when the client is loaded.
*/
function loadClient(callback) {
gapi.client.load('drive', 'v2', callback);
}
/**
* Print a file's metadata.
*
* #param {String} fileId ID of the file to print metadata for.
*/
function printFile(fileId) {
var request = gapi.client.drive.files.get({
'fileId': fileId
});
request.execute(function(resp) {
if (!resp.error) {
console.log('Title: ' + resp.title);
console.log('Description: ' + resp.description);
console.log('MIME type: ' + resp.mimeType);
} else if (resp.error.code == 401) {
// Access token might have expired.
checkAuth();
} else {
console.log('An error occured: ' + resp.error.message);
}
});
}
</script>
</body>
</html>

By setting immediate=true you are suppressing the auth popup.
It should be false the first time through and is generally set to true thereafter for each hourly refresh.

Related

calling a Google Cloud Functions with parameters from browser using Javascript

I am trying to stream some events in batches from a mobile web site to BigQuery, and I am trying to trigger a Google Cloud Function to do this via parameters.
I've reached the point to initilise de script, but how do I call a Google Cloud Function with param?
<script src="https://apis.google.com/js/api.js"></script>
<script>
function start() {
// 2. Initialize the JavaScript client library.
gapi.client.init({
'apiKey': 'YOUR_API_KEY',
// Your API key will be automatically added to the Discovery Document URLs.
'discoveryDocs': ['https://people.googleapis.com/$discovery/rest'],
// clientId and scope are optional if auth is not required.
'clientId': 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
'scope': 'profile',
}).then(function() {
// 3. Initialize and make the API request.
return gapi.client.people.people.get({
'resourceName': 'people/me',
'requestMask.includeField': 'person.names'
});
}).then(function(response) {
console.log(response.result);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
};
// 1. Load the JavaScript client library.
gapi.load('client', start);
</script>
I hope you found a solution for it... but I usually do:
var getPeople = gapi.client.people.people.get({
'resourceName': 'people/me',
'requestMask.includeField': 'person.names'
});
getPeople.execute(function(response) {
console.log(response.result);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});

API key not valid error when trying to get profile data

I'm trying to test Google login API. I want to retrieve some basic data after the client logs.
I created a Google API Console project and client ID (https://developers.google.com/identity/sign-in/web/devconsole-project)
Here is google official code (https://developers.google.com/api-client-library/javascript/samples/samples#LoadinganAPIandMakingaRequest):
<html>
<head>
</head>
<body>
<script type="text/javascript">
function handleClientLoad() {
// Loads the client library and the auth2 library together for efficiency.
// Loading the auth2 library is optional here since `gapi.client.init` function will load
// it if not already loaded. Loading it upfront can save one network request.
gapi.load('client:auth2', initClient);
}
function initClient() {
// Initialize the client with API key and People API, and initialize OAuth with an
// OAuth 2.0 client ID and scopes (space delimited string) to request access.
gapi.client.init({
apiKey: '5v2RzP7-xyQGNjxrD5suoPL9',
discoveryDocs: ["https://people.googleapis.com/$discovery/rest?version=v1"],
clientId: '298062822261-e5c09q8191mkho0o7n3n3obiq2eq2p3f.apps.googleusercontent.com',
scope: 'profile'
}).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());
});
}
function updateSigninStatus(isSignedIn) {
// When signin status changes, this function is called.
// If the signin status is changed to signedIn, we make an API call.
if (isSignedIn) {
makeApiCall();
}
}
function handleSignInClick(event) {
// Ideally the button should only show up after gapi.client.init finishes, so that this
// handler won't be called before OAuth is initialized.
gapi.auth2.getAuthInstance().signIn();
}
function handleSignOutClick(event) {
gapi.auth2.getAuthInstance().signOut();
}
function makeApiCall() {
// Make an API call to the People API, and print the user's given name.
gapi.client.people.people.get({
resourceName: 'people/me'
}).then(function(response) {
console.log('Hello, ' + response.result.names[0].givenName);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
}
</script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
<button id="signin-button" onclick="handleSignInClick()">Sign In</button>
<button id="signout-button" onclick="handleSignOutClick()">Sign Out</button>
</body>
</html>
ClientId and apikey are from my google api.
I receive error 400
{
"error": {
"code": 400,
"message": "API key not valid. Please pass a valid API key.",
"status": "INVALID_ARGUMENT",
"details": [
{
"#type": "type.googleapis.com/google.rpc.Help",
"links": [
{
"description": "Google developers console",
"url": "https://console.developers.google.com"
}
]
}
]
}
}
I don't understand what's wrong whit my api key. I followed all the steps from google documentation.
It seems you are using the client secret as API key. Isn't it?
To obtain an API key you must create it.
Under credentials (dev console) click on create credential, and then 'API Key'

"GAPI is not defined" message

I'm trying to use the Google Sheets API for inclusion in my web app, but I keep receiving a error specifying that the gapi library is not defined. I've tried delay the request to the server by using the ComponentDidMount life cycle method, and even using a timeout in that method, but I keep receiving the same error. How can I have the gapi library defined for use then in my app ?
import React from 'react';
var CLIENT_ID = '';
var SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"];
export default class MyNavbar extends React.Component {
constructor(props) {
super(props);
}
componentDidMount(){
this.checkAuth();
}
/**
* Check if current user has authorized this application.
*/
checkAuth(){
gapi.auth.authorize(
{
'client_id': CLIENT_ID,
'scope': SCOPES.join(' '),
'immediate': true
}, this.handleAuthResult());
}
/**
* Handle response from authorization server.
*
* #param {Object} authResult Authorization result.
*/
handleAuthResult(authResult) {
var authorizeDiv = document.getElementById('authorize-div');
if (authResult && !authResult.error) {
// Hide auth UI, then load client library.
authorizeDiv.style.display = 'none';
loadSheetsApi();
} else {
// Show auth UI, allowing the user to initiate authorization by
// clicking authorize button.
authorizeDiv.style.display = 'inline';
}
}
/**
* Initiate auth flow in response to user clicking authorize button.
*
* #param {Event} event Button click event.
*/
handleAuthClick(event) {
gapi.auth.authorize(
{client_id: CLIENT_ID, scope: SCOPES, immediate: false},
handleAuthResult);
return false;
}
/**
* Load Sheets API client library.
*/
loadSheetsApi() {
var discoveryUrl =
'https://sheets.googleapis.com/$discovery/rest?version=v4';
gapi.client.load(discoveryUrl).then(listMajors);
}
/**
* Print the names and majors of students in a sample spreadsheet:
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
*/
listMajors() {
gapi.client.sheets.spreadsheets.values.get({
spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
range: 'Class Data!A2:E',
}).then(function(response) {
var range = response.result;
if (range.values.length > 0) {
appendPre('Name, Major:');
for (i = 0; i < range.values.length; i++) {
var row = range.values[i];
// Print columns A and E, which correspond to indices 0 and 4.
appendPre(row[0] + ', ' + row[4]);
}
} else {
appendPre('No data found.');
}
}, function(response) {
appendPre('Error: ' + response.result.error.message);
});
}
/**
* Append a pre element to the body containing the given message
* as its text node.
*
* #param {string} message Text to be placed in pre element.
*/
appendPre(message) {
var pre = document.getElementById('output');
var textContent = document.createTextNode(message + '\n');
pre.appendChild(textContent);
}
render(){
return (
<div>
<h1>Hello World My Name Is Justin 2</h1>
<div id="authorize-div"></div>
<pre id="output"></pre>
</div>
);
}
}
Here try this.
import React from 'react';
import asyncLoad from 'react-async-loader'; // for loading script tag asyncly `npm i --save react-async-loader`
const CLIENT_ID = '';
const SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"];
// For making gapi object passed as props to our component
const mapScriptToProps = state => ({
// gapi will be this.props.gapi
gapi: {
globalPath: 'gapi',
url: 'https://your-gapi-url'
}
});
#asyncLoad(mapScriptToProps)
class MyNavbar extends React.Component {
constructor(props) {
super(props);
this.gapi = null;
// You need to bind methods to this class's object context. (i.e this)!
this.checkAuth = this.checkAuth.bind(this);
this.handleAuthResult = this.authResult.bind(this);
this.handleAuthClick = this.handleAuthClick.bind(this);
this.loadSheetsApi = this.loadSheetsApi.bind(this);
this.listMajors = this.listMajors.bind(this);
}
componentDidMount() {
// Check is gapi loaded?
if (this.props.gapi !== null) {
this.checkAuth();
}
}
componentWillReceiveProps({ gapi }) {
if (gapi!== null) {
this.checkAuth();
}
}
/**
* Check if current user has authorized this application.
*/
checkAuth() {
// this will give you an error of gapi is not defined because there is no
// reference of gapi found globally you cannot access global object which are
// not predefined in javascript( in this case its window.gapi ).
// properties added by Programmer cannot be accessed directly( if it's not in the same file as well as the same scope!) in commonjs modules. Because they
// don't' run in a global scope. Any variable in another module which is not
// exported, will not be available to other modules.
this.gapi = window.gapi; // you can do like this. Now you can access gapi in all methods if this class.
this
.gapi
.auth
.authorize({
'client_id': CLIENT_ID,
'scope': SCOPES.join(' '),
'immediate': true
}, this.handleAuthResult());
}
/**
* Handle response from authorization server.
*
* #param {Object} authResult Authorization result.
*/
handleAuthResult(authResult) {
var authorizeDiv = document.getElementById('authorize-div');
if (authResult && !authResult.error) {
// Hide auth UI, then load client library.
authorizeDiv.style.display = 'none';
loadSheetsApi();
} else {
// Show auth UI, allowing the user to initiate authorization by clicking
// authorize button.
authorizeDiv.style.display = 'inline';
}
}
/**
* Initiate auth flow in response to user clicking authorize button.
*
* #param {Event} event Button click event.
*/
handleAuthClick(event) {
// gapi.auth.authorize( here also gapi is not defined
this
.gapi
.auth
.authorize({
client_id: CLIENT_ID,
scope: SCOPES,
immediate: false
}, handleAuthResult);
return false;
}
/**
* Load Sheets API client library.
*/
loadSheetsApi() {
var discoveryUrl = 'https://sheets.googleapis.com/$discovery/rest?version=v4';
// also will give your error
// for gapi being not defined.
// gapi.client.load(discoveryUrl).then(listMajors);
this
.gapi
.client
.load(discoveryUrl)
.then(listMajors);
}
/**
* Print the names and majors of students in a sample spreadsheet:
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
*/
listMajors() {
this.gapi
.client
.sheets
.spreadsheets
.values
.get({spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms', range: 'Class Data!A2:E'})
.then(function (response) {
var range = response.result;
if (range.values.length > 0) {
appendPre('Name, Major:');
for (i = 0; i < range.values.length; i++) {
var row = range.values[i];
// Print columns A and E, which correspond to indices 0 and 4.
appendPre(row[0] + ', ' + row[4]);
}
} else {
appendPre('No data found.');
}
}, function (response) {
appendPre('Error: ' + response.result.error.message);
});
}
/**
* Append a pre element to the body containing the given message
* as its text node.
*
* #param {string} message Text to be placed in pre element.
*/
appendPre(message) {
// as you can see. You are accessing window.document as document.
// its fine because its defined in javascript (implicitly),
// not explicitly by programmer(here you!).
var pre = document.getElementById('output');
var textContent = document.createTextNode(message + '\n');
pre.appendChild(textContent);
}
render() {
return (
<div>
<h1>Hello World My Name Is Justin 2</h1>
<div id="authorize-div"></div>
<pre id="output"></pre>
</div>
);
}
}
export default MyNavbar;
You need to load the gapi library before bundle.js in index.html file, or better you can load the gapi js script async with react-async-loader.
Here's how you can do it :
import React, { Component, PropTypes } from 'react';
import asyncLoad from 'react-async-loader'; // for loading script tag asyncly
// For making gapi object passed as props to our component
const mapScriptToProps = state => ({
gapi: {
globalPath: 'gapi',
url: 'https://your-gapi-url'
}
});
// decorate our component
#asyncLoad(mapScriptToProps)
class yourComponent extends Component {
componentDidMount() {
// Check is gapi loaded?
if (this.props.gapi !== null) {
this.checkAuth();
}
}
componentWillReceiveProps({ gapi }) {
if (gapi!== null) {
this.checkAuth();
}
}
checkAuth = () => {
// Better check with window and make it available in component
this.gapi = window.gapi;
this.gapi.auth.authorize({
'client_id': CLIENT_ID,
'scope': SCOPES.join(' '),
'immediate': true
}, this.handleAuthResult);
}
handleAuthResult = (authData) => {
// Your auth loagic...
}
render() {
return ( <div>
{ this.props.gapi &&
<YourSpreadsheetOrWhatever data={ this.getData() } />
}
</div>)
}
}
Try replacing your code with this and check if it works.
I found this project https://github.com/rlancer/gapi-starter it may be helpful.
Google Login & API + ReactJS + Flow + Webpack starter kit
Google API's are great but they were designed before the module partner of Javascript programing became popular. This starter fixes that handing Google login and library loading for you.
Get the Code!
git clone https://github.com/rlancer/gapi-starter.git
cd gapi-starter
npm install
You need to load the gapi library before bundle.js in index.html file as :
<script src="https://apis.google.com/js/api.js"></script>
And then you just need to initialize your gapi variablesas :
let gapi = window.gapi;

Use custom image for google signin button

I want to provide users a facility to sign in with google. However, I want to use my image(only image, no css) as "sign in with google" button. I am using the following code:
<div id="mySignin"><img src="images/google.png" alt="google"/></div>
I am also using gapi.signin.render function as mentioned on google developer console. The code is:
<script src="https://apis.google.com/js/client:platform.js" type="text/javascript"></script>
<script>
function render(){
gapi.signin.render("mySignIn", {
// 'callback': 'signinCallback',
'clientid': 'xxxx.apps.googleusercontent.com',
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schema.org/AddAction',
'scope': 'profile'
});
}
The problem is that google signin popup is not opening and I cannot figure out how to solve it. Please suggest. Thanks in advance.
<script type="text/JavaScript">
/**
* Handler for the signin callback triggered after the user selects an account.
*/
function onSignInCallback(resp) {
gapi.client.load('plus', 'v1', apiClientLoaded);
}
/**
* Sets up an API call after the Google API client loads.
*/
function apiClientLoaded() {
gapi.client.plus.people.get({userId: 'me'}).execute(handleEmailResponse);
}
/**
* Response callback for when the API client receives a response.
*
* #param resp The API response object with the user email and profile information.
*/
function handleEmailResponse(resp) {
var primaryEmail;
var jsonobj=JSON.stringify(resp);alert(jsonobj);
var uid= jsonobj.id;
var user_name1= jsonobj.name;
for (var i=0; i < resp.emails.length; i++) {
if (resp.emails[i].type === 'account') primaryEmail = resp.emails[i].value;
}
/* document.getElementById('response').innerHTML = 'Primary email: ' +
primaryEmail + '<br/>id is: ' + uid; */
}
To use an image as your "Google Sign-in" button, you can use the GoogleAuth.attachClickHandler() function from the Google javascript SDK to attach a click handler to your image. Replace <YOUR-CLIENT-ID> with your app client id from your Google Developers Console.
HTML example:
<html>
<head>
<meta name="google-signin-client_id" content="<YOUR-CLIENT-ID>.apps.googleusercontent.com.apps.googleusercontent.com">
</head>
<body>
<image id="googleSignIn" src="img/your-icon.png"></image>
<script src="https://apis.google.com/js/platform.js?onload=onLoadGoogleCallback" async defer></script>
</body>
</html>
Javascript example:
function onLoadGoogleCallback(){
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: '<YOUR-CLIENT-ID>.apps.googleusercontent.com',
cookiepolicy: 'single_host_origin',
scope: 'profile'
});
auth2.attachClickHandler(element, {},
function(googleUser) {
console.log('Signed in: ' + googleUser.getBasicProfile().getName());
}, function(error) {
console.log('Sign-in error', error);
}
);
});
element = document.getElementById('googleSignIn');
}
For those who come to here trying to get the button work out: The code below should do the trick.
It looks like the 'callback' method doesn't seem to work not sure if this is something to do with Vue as I am building it on Vue, or Google changed it as this was posted 5 years ago. Anyways, use the example below.
window.onload =() =>{
var GoogleUser = {}
gapi.load('auth2',() =>{
var auth2 = gapi.auth2.init({
client_id: '<client-unique>.apps.googleusercontent.com',
cookiepolicy: 'single_host_origin',
scope: 'profile'
});
auth2.attachClickHandler(document.getElementById('googleSignup'), {},
(googleUser) =>{
console.log('Signed in: ' + googleUser.getBasicProfile().getName());
},(error) =>{
console.log('Sign-in error', error);
}
);
});
}
Change 'client_id' to your client id, and element id to your customized button id.
I hope this saves time for anyone!
Plus: I ended up using the code below, which is clearer:
window.onload = () => {
gapi.load('auth2', () => {
let auth2 = gapi.auth2.init({
client_id: '<client_id>.apps.googleusercontent.com',
cookiepolicy: 'single_host_origin',
scope: 'profile email'
});
document.getElementById('googleSignup').addEventListener('click',() => {
auth2.signIn().then(() => {
let profile = auth2.currentUser.get().getBasicProfile();
... profile functions ...
}).catch((error) => {
console.error('Google Sign Up or Login Error: ', error)
});
});;
});
}

Google drive Public

I am working with Google drive picker, where once an item is selected from Google drive a url is produced. The problem is that that url is only accessible by the owner, and hence not public. I want the URL to be publicly accessible.
Hence, i've looked into the following guide:
https://developers.google.com/picker/docs/reference#Response.Documents
and feel that the Document.AUDIENCE class would be best applicable, however I do not know how to add that criteria into the below google drive picker example code.
Any help would be greatly appreciated.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Picker Example</title>
<script type="text/javascript">
// The Browser API key obtained from the Google Developers Console.
var developerKey = 'xxxxxxxYYYYYYYY-12345678';
// The Client ID obtained from the Google Developers Console. Replace with your own Client ID.
var clientId = "1234567890-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com"
// Scope to use to access user's photos.
var scope = ['https://www.googleapis.com/auth/photos'];
var pickerApiLoaded = false;
var oauthToken;
// Use the API Loader script to load google.picker and gapi.auth.
function onApiLoad() {
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
}
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 picking user Photos.
function createPicker() {
if (pickerApiLoaded && oauthToken) {
var picker = new google.picker.PickerBuilder().
addView(google.picker.ViewId.PHOTOS).
setOAuthToken(oauthToken).
setDeveloperKey(developerKey).
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
}
// A simple callback implementation.
function pickerCallback(data) {
var url = 'nothing';
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
url = doc[google.picker.Document.URL];
}
var message = 'You picked: ' + url;
document.getElementById('result').innerHTML = message;
}
</script>
</head>
<body>
<div id="result"></div>
<!-- The Google API Loader script. -->
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
To add public permissions to the selected file. You will need to use the drive api to add file permissions
Please see https://developers.google.com/drive/v2/reference/permissions/insert
You will need to insert a permission to the file with role set to 'reader' and the type to 'anyone'
You can refer to the javascript implementation in the example
/**
* Insert a new permission.
*
* #param {String} fileId ID of the file to insert permission for.
* #param {String} value User or group e-mail address, domain name or
* {#code null} "default" type.
* #param {String} type The value "user", "group", "domain" or "default".
* #param {String} role The value "owner", "writer" or "reader".
*/
function insertPermission(fileId, value, type, role) {
var body = {
'value': value,
'type': type,
'role': role
};
var request = gapi.client.drive.permissions.insert({
'fileId': fileId,
'resource': body
});
request.execute(function(resp) { });
}
To elaborate on #Sam's answer, here is how you would do it without using the gapi.client.drive Javascript API.
Let's say that some_id is your document id:
request = gapi.client.request({
path: '/drive/v2/files/some_id/permissions',
method: 'POST',
body: {
role: 'reader'
type: 'anyone'
}
});
request.execute(function (res) {
console.log(res);
})
Which generates a request to https://content.googleapis.com/drive/v2/files/some_id/permissions?alt=json with this body: {role: "reader", type: "anyone"}
Here is the result you will get:
{
"kind": "drive#permission",
"etag": "some etage",
"id": "anyone",
"selfLink": "https://www.googleapis.com/drive/v2/files/some_id/permissions/anyone",
"role": "reader",
"type": "anyone"
}

Categories

Resources