From GoogleYolo (Google Smart Lock), what does "Invalid audience" mean? - google-api

The error/warning message (written by obfuscated code from https://www.gstatic.com//mss/boq-identity//js/k=boq-identity.IdentityYoloWebModuleset.en.5jYiE0Kzqd0.O/m=yolo_frame_library/rt=j/d=1/rs=AOaEmlHvGDn8UcjjSaG2zLiaoxdbMowW7g to the console, Chrome Version 65.0.3325.162) is, "Invalid audience. Please use the Google Cloud console (https://console.developers.google.com), and create a valid OAuth2 web client."
I was following https://developers.google.com/identity/one-tap/web/get-started -- does anyone know if a single-archive fully-complete example exists anywhere? (I looked.)
My code goes as follows, and I did set https://localhost:8000 and a personal website with https as allowed origins for the client ID in question, which are where I'm testing this.
<html>
<head>
<script src="https://smartlock.google.com/client"></script>
</head>
<body>
<script>
const clientID = "...";
const authUri = "https://accounts.google.com";
window.onGoogleYoloLoad = (googleyolo) =>
{
const retrievePromise = googleyolo.retrieve(
{
supportedAuthMethods: [ authUri ],
supportedIdTokenProviders: [ { uri: authUri, clientId: clientID } ]
});
}
</script>
</body>
</html>
Moreover, I tested similar code except with googleyolo.hint then googleyolo.retrieve and the other way around. Both ways, each time I refreshed the page, it was as if I have never visited before -- and that's whether or not I was logged in to Google in Chrome. So after the hint completes, what needs done to save or store that status?

I was able to find some working examples located here -
https://www.codeproject.com/Articles/579564/JavaScript-oAuth
https://developers.google.com/identity/sign-in/web/sign-in
I setup a test script using the examples from the CodeProject link, and just commented out the pieces I did not need.
<div class="loginDiv">
<div id="googlelogin">Google</div>
</div>
<div style="clear:both;" id="userinfo"></div>
var clientId = '.....';
var scopes = 'https://www.googleapis.com/auth/plus.me';
Enjoy!

Related

Handling errors with reCAPTCHA v3

I have reCAPTCHA v3 set up on my page:
<script src="https://www.google.com/recaptcha/api.js?render=MY_KEY"></script>
If internet connectivity becomes unavailable or unreliable, reCAPTCHA will insert this HTML at the bottom of my page:
<div>
<div>
Could not connect to the reCAPTCHA service. Please check your internet connection and reload to get a reCAPTCHA challenge.
</div>
</div>
I would much rather handle this error in my JavaScript so I can display it to the user in a better way. However, the documentation for v3 doesn't indicate how to do this.
Any thoughts on how to catch this error?
You can put an onerror handler in the script tag itself:
<script src="https://www.google.com/recaptcha/api.js?render=MY_KEY" onerror="error_handler()">
But I think what you want is more along the lines of what reCAPTCHA v2 offers:
widgetId = grecaptcha.render('example1', {
'sitekey' : 'your_site_key',
'theme' : 'light',
'error-callback' : error_handler()
});
I doubt that works but there is another way. You just need to monitor the DOM for changes since you know that when there is an error Google will add a div to your page. You can do that with MutationObserver.
var m = new MutationObserver(function (mutationRecords) {
this.disconnect();
error_handler();
});
m.observe(document.body, {childList: true});
{childList: true} tells the MutationObserver to detect nodes added to the DOM and passes them to the callback function as the parameter mutationRecords (which contains array of MutationRecord objects). From there it's up to you what to do next.
This should at least be enough to get you started!

How to read data using the spreadsheets API without using oauth2

This is Yet another error 403 on Google Sheets API. Um trying to read the data from a Spreadsheet and expose it on a website, using some custom HTML filters.
So, there is this question:
Error 403 on Google Sheets API
Still, I cannot figure out what to do. I have setup my service account in the google cloud platform, granted it permissions to access my Spreadsheet - I have even made my SpreadSheet accessible via link (but that is restricted to emails from my organization, so it seems useless anyway). I've also activated domain-wide delegation for my service account - didn't make any difference at all. I'm pretty sure the issue is not related to a wrong key or some typo because, when I remove the access to the service email from the sheet, I steel get a 403 error, but it comes with a message saying the caller doesn't have access to that spreadsheet.
People keep mentioning OAuth, but I don't want to use that, since I'm intending to use a simple API access, as in this Google GitHub example. I'm using my business account, so there might be some issue related to that.
Here is the HTML (which I'm running from a simple HTTP server on python, not directly, given the fact the GAPI doesn't handle localhost/ sources very well):
<!DOCTYPE html>
<html>
<head>
<title>Google Sheets API Quickstart</title>
<meta charset="utf-8" />
</head>
<body>
<p>Google Sheets API Quickstart</p>
<!--Add buttons to initiate auth sequence and sign out-->
<button id="authorize_button" style="display: none;">Authorize</button>
<button id="signout_button" style="display: none;">Sign Out</button>
<pre id="content" style="white-space: pre-wrap;"></pre>
<script type="text/javascript">
// Client ID and API key from the Developer Console
var API_KEY = 'My-API-KEY';
var DISCOVERY_DOCS = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
var SCOPES = "https://www.googleapis.com/auth/spreadsheets.readonly";
function handleClientLoad() {
gapi.load('client', initClient);
}
function initClient() {
gapi.client.init({
apiKey: API_KEY,
discoveryDocs: DISCOVERY_DOCS
}).then(function(){listMajors();})
}
function appendPre(message) {
var pre = document.getElementById('content');
var textContent = document.createTextNode(message + '\n');
pre.appendChild(textContent);
}
function listMajors() {
gapi.client.sheets.spreadsheets.values.get({
spreadsheetId: 'my-spreadsheet-id',
range: 'Sheet1!A1:A10',
}).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);
});
}
</script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === lete') this.onload()">
</script>
</body>
</html>
Does anyone have anyclue on what I'm missing, or what else can I try?
Edit: sharing the spreadsheet publicly is not an option. The is a business email, and, therefore, the only option I've got here is sharing it domain wide, as I've already stated above. Also, this is a business spreadsheet, and therefofe contains sentitive data. Doesn't really make sense to expose it publicly. Besides that, I've already shared the spreadsheet with the service email. What I'm trying to achieve, after all, is to read the data from the spreadsheet without using oauth, and emdding it on a website (I know there is a built-in embed tool, but that doesn't suit me because I need to add a html filter).
If you try to access a Spreadsheet that is not public, you will have to use OAuth 2.0. Since it is not a public resource, you have to use the credentials of an account that has access to this resource.
In the example you provided, they are accessing a public resource, so the API key is enough. That's not your case.
Reference:
Using OAuth 2.0 to Access Google APIs

Prompt User to Upload file in Dialog Flow with MS Bot Framwork v4

I have a dialog flow that will require a user to upload a file/files. I would like to prompt the user and have them click on a button to open a file browse window to select the file they want to upload. I do not want to use the file chooser in the WebChat window text entry box (Users find this confusing). Is this possible? I saw in the documentation for v3 that there is a AttachmentPrompt dialog. However in the documentation for v4 I only see it mentioned in a one liner here... https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0 however other than that which sounds promising there appears to be no documentation on this functionality.
Thanks for any help you can provide!
PromptAttachment does not define client side rendering, or client side file upload code. In order to have the WebChat control respond to a custom button, you will need to provide an Attachment Middleware for the Web Chat control, and have the bot send a custom attachment type.
Custom Attachment:
private class FileUpload : Attachment
{
public FileUpload()
: base("application/uploadAttachment") { }
}
Replying with FileUpload attachment:
var reply = activity.CreateReply("Upload a File");
reply.Attachments.Add(new FileUpload());
await connector.Conversations.SendToConversationAsync(reply);
Page hosting Web Chat:
<!DOCTYPE html>
<html>
<body>
<div id="webchat" />
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/react#16.5.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.5.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-redux#5.0.7/dist/react-redux.min.js"></script>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<script>
function uploadFile() {
document.querySelector('[title="Upload file"]').click();
}
</script>
<script type="text/babel">
var chatbot = new WebChat.createDirectLine({
token: 'YourToken',
webSocket: true,
});
const attachmentMiddleware = () => next => card => {
switch (card.attachment.contentType) {
case 'application/uploadAttachment':
return (<button type="button" onClick={uploadFile}>Upload file</button>);
default:
return next(card);
}
};
WebChat.renderWebChat({
directLine: chatbot,
botAvatarInitials: 'Bot',
attachmentMiddleware,
}, document.getElementById('webchat'));
</script>
</body>
</html>

Combining reCAPTCHA v2 and v3

I'm keen to use reCAPTCHA v3 for logins and stuff, but I'm unsure what to do with a 'low rating', it doesn't feel safe to deny access with no way for the user to move forward. What feels like a more complete solution would be to combine the "rating" from v3 with a puzzle challenge from v2 if the score is too low. How are other people approaching this issue?
Also, it appears that v3's grecaptcha.execute returns a similar result to v2, that is too say that it's not returning a rating, just a TOKEN which is verified in a similar way to v2?
I've code i found to demonstrate that they can both be used in the same HTML...
<!-- https://github.com/google/recaptcha/issues/279 -->
<script src="https://www.google.com/recaptcha/api.js?onload=v2_onload"></script>
<script src="https://www.google.com/recaptcha/api.js?onload=v3_onload&render=V3_SITE_KEY"></script>
<script src='https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY'></script>
<div class="g-recaptcha" data-size="invisible" data-sitekey="V2_SITE_KEY" data-callback="v2_callback"></div>
<script type="text/javascript">
function v2_onload() { console.log('v2 loaded'); }
function v3_onload() { console.log('v3 loaded'); }
function v2_callback(token) { console.log('v2 token: ' + token); }
function v3_callback(token, score) { console.log('v3 token: ' + token + " ----- " + score); }
// call these manually
function test_v2() { grecaptcha.execute(); }
function test_v3() {
grecaptcha.execute('V3_SITE_KEY' , {action:'thisIsATest' }).then(v3_callback);
}
I have concerns then that if v3 requires sever-side validation, in order to implement v2 as well, either a page reload to invoke v2 (when server-side says "low rating" then reload and enable v2) OR v3 sever-side validation could be done via an ajax call, but that feels like something that can be inspected and manipulated by a bot (grab ajax response, change 'no' to 'yes' and then have the bot call the 'callback' function itself to gain access).
Any help or suggestions would be appreciated.
It looks like there is an answer to this question on the official Frequently Asked Questions website of reCAPTCHA.
Can I run reCAPTCHA v2 and v3 on the same page?
To do this, load the v3 site key as documented, and then explicitly render v2 using grecaptcha.render.
<html>
<head>
<title>reCAPTCHA demo: Running both v2 and v3</title>
<script src="https://www.google.com/recaptcha/api.js?render=v3_site_key"></script>
<script>
grecaptcha.ready(() => {
grecaptcha.render('html_element', {
'sitekey' : 'v2_site_key'
});
});
</script>
<script>
function onSubmit() {
grecaptcha.ready(() => {
grecaptcha.execute('v3_site_key', {action: 'homepage'}).then((token) => {
...
});
});
}
</script>
</head>
</html>
Wouldn't it be simplest to just send the token with your form post and double check it server side? I know you're still possibly allowing a bot to post data into your system, but a bot that can sneak by google should be pretty rare. And the first thing your sever side logic should do is verify the token, which can't easily be faked. That said in my initial analysis of google V3(10K requests) the bot detection was solidly binary, in that all the scores were above or below .5 . Google in their documentation recommends different strategies for how to deal with suspicious traffic based on the scenario.
https://developers.google.com/recaptcha/docs/v3.

Google ReCaptcha without PHP plugin

I understand the cross-domain error when using ajax to try to obtain information from another website but according to jQuery you should be able to use a jsonp request instead. I am stumped on how to achieve this when trying to display recaptcha. The issue is I am unable to use the plugin to achieve this, which would make it so much easier.
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
<script type="text/javascript">
function showRecaptcha() {
Recaptcha.create("// removed for example", 'captchadiv', {
tabindex: 1,
theme: "red",
callback: Recaptcha.focus_response_field
});
}
jQuery(document).ready(function(){
showRecaptcha('recaptcha_div');
jQuery('#contact-form').submit(function(){
var challenge = Recaptcha.get_challenge();
var response = Recaptcha.get_response();
var ip = "<?php print $_SERVER['REMOTE_ADDR'] ?>";
var private = "// removed for example";
var requestUrl = "http://www.google.com/recaptcha/api/verify?privatekey=" + private + "&remoteip=" + ip + "&challenge=" + challenge + "&response=" + response;
jQuery.getJSON(requestUrl, function(json) {
alert("what");
});
})
});
</script>
<form id="">
// Form stuff
</form>
<div id="captchadiv"></div>
<input type="submit" name="submit" id="form-submit">
How should I call this to googles server and obtain the correct callback. It's basically going to return a true or false. I either get the infamous Access-Control-Allow-Login or or an error regarding plain/text. Anyone with suggestions?
1) Google does not support JSONP output. Why? Go to 2).
2) reCAPTCHA is meant to be validated on server side code. Why? Go to 3).
3) Spammers can easily bypass your client side validation code, thus rendering any CAPTCHA solution pointless.
You can try this way, Invisible reCAPTCHA
https://developers.google.com/recaptcha/docs/invisible

Resources