Google Sign-In JavaScript client not working on PWA App - oauth

Since yesterday when I use the gapi.auth2 to do a Google Sign-in on an installed PWA app on Android, the App opens the browser window to select the user, but it remains blank.
The same page on the Chrome browser on Android open the user selection as usual. The code is the same, from the same server. The code was not modified in more than 15 days. I presume the problem is some change in the gapi JS client code from Google servers.
Inspecting the PWA Google Sign-in tab on chrome shows the following error:
Uncaught Failed to get parent origin from URL hash!
The origins on Google Developer Console are ok.
Anyone has any clue how to solve this?
Edit1: Code chunk
initGoogle() {
this.ngRedux.dispatch({ type: SN_INIT_GOOGLE });
Observable.create((observer: Observer<any>) => {
let head = document.getElementsByTagName('head');
(<any>window).__ongload = () => {
gapi.load('auth2', () => {
gapi.auth2.init({
client_id: `${AppConfig.google.clientID}`
}).then(() => {
this.auth2 = gapi.auth2.getAuthInstance();
this.googleInitiated();
observer.complete();
}, (err) => {
this.log.error(err);
observer.error(err);
});
});
};
let script: HTMLScriptElement = document.createElement('script');
script.src = 'https://apis.google.com/js/platform.js?onload=__ongload';
script.type = 'text/javascript';
head[ 0 ].appendChild(script);
}).pipe(
timeout(AppConfig.google.timeout),
retry(AppConfig.google.retries),
catchError(error => {
this.googleInitError();
return observableEmpty();
}),
take(1)
).subscribe();
}
async googleLogin(scope: string = 'profile email', rerequest: boolean = false, type: string = SN_GOOGLE_LOGIN): Promise<GoogleUser> {
let goopts = {
scope: this.ngRedux.getState().socialNetworks.getIn([ 'google', 'grantedScopes' ]),
prompt: rerequest ? 'consent' : undefined
};
try {
const user: GoogleUser = await this.auth2.signIn(<any>goopts);
...
return user;
} catch (error) {
...
return error;
}
}
Edit 2: Error screenshot
Screenshot

I had the similar issue as mentioned here. I had not registered my domain under Credential -> My OAuth Client ID -> Authorized JavaScript origins. By adding, it started working. Check the similar case for your app. It may help.

This bug should be fixed. Cannot reproduce it any more.

Related

Supabase Auth - redirectTo not working for OAuth

I am switching from Flutter to Supabase and am running into an issue with Authentication. Although I can successfully launch the URL with the correct redirect value, I keep getting redirected to the site URL which should only be used for web, not iOS or Android. Below is the function I am using for Apple but this is happening with all other providers as well.
const isWeb = Platform.OS === "web";
const redirectTo = isWeb
? "https://web.example.com/login-callback/"
: "com.example.react://login-callback/";
export const signInWithApple = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "apple",
options: {
redirectTo: redirectTo,
},
});
if (error !== null) {
console.log(error?.message);
return "error";
} else {
console.log(data);
Linking.openURL(data.url);
return "success";
}
};
The URL that gets logged before launching is correct, for example, LOG {"provider": "apple", "url": "https://api.example.com/auth/v1/authorize?provider=apple&redirect_to=com.example.react%3A%2F%2Flogin-callback%2F"}, but I always get redirected to something like https://web.example.com/#access_token=*****. I had a similar issue with Flutter, and that was because I had not added the additional redirect in Supabase but I already did that. I also confirmed that I have CFBundleURLSchemes set in the info.plist for iOS but that did not fix it.
IF SELF-HOSTING:
Check that you do not have spaces after commas in ADDITIONAL_REDIRECT_URLS.
Correct ✅ :
ADDITIONAL_REDIRECT_URLS="URL,URL,URL"
Incorrect ❌ :
ADDITIONAL_REDIRECT_URLS="URL, URL, URL"

how to redirect back to app login page after authentication in ionic capacitor project

i have recently switched to capacitor, my app uses sso login after login and getting token, it used to redirect back to app, but after using capacitor, i m getting the token but not getting redirected to the app.
below is the previous code that was working :
platform.ready().then(() => {
this.deeplinks.routeWithNavController(this.navChild, {
'/form-list/:token': this.router.navigate(['login'])
}).subscribe((match) => {
console.log('Successfully routed', match.$args);
}, (nomatch) => {
console.log('Unmatched Route', nomatch);
});
}
after switching to capacitor and changing the code accordingly after going through all the documents, the new code is :
initializeApp() {
App.addListener('appUrlOpen', (data: any) => {
this.zone.run(() => {
console.log('Successfully routed',data);
const slug = data.url.split(".app").pop();
if (slug) {
this.router.navigate(['login']);
}
});
});
}
Please help in getting this issue resolved, have already spend good amount of time in resolving this.
Any help is appreciated.Thanks

"ReferenceError: calendar is not defined" encountered in NodeJS but same code works in API Test Console in Google

Trying to follow this blog post Create a Smart Voicemail with Twilio, JavaScript and Google Calendar
When I run the code in Google Developer API Test Console, it works. However, the same parameters called within Twilio Function which runs NodeJS returns an error "ReferenceError: calendar is not defined"
I've made the Google Calendar events public and I've tried viewing it using the public URL and it works too. For someone reason calling it withing Twilio Functions is resulting in an error.
const moment = require('moment');
const { google } = require('googleapis');
exports.handler = function(context, event, callback) {
// Initialize Google Calendar API
const cal = google.calendar({
version: 'v3',
auth: context.GOOGLE_API_KEY
});
//Read Appointment Date
let apptDate = event.ValidateFieldAnswer;
var status = false;
const res = {
timeMin: moment().toISOString(),
timeMax: moment().add(10, 'minutes').toISOString(),
items: [{
id: context.GOOGLE_CALENDAR_ID
}]
};
console.log(res);
cal.freebusy.query({
resource: res
}).then((result) => {
const busy = result.data.calendars[calendar].busy;
console.log("Busy: " + busy);
if (busy.length !== 0) {
let respObj1 = {
"valid": false
};
console.log("Failed");
callback(null, respObj1);
} else {
let respObj1 = {
"valid": true
};
console.log("Success");
callback(null, respObj1);
}
}).catch(err => {
console.log('Error: checkBusy ' + err);
let respObj1 = {
"valid": false
};
callback(null, respObj1);
});
};
Have you encountered this before or is anyone able to identify the issue here?
Thanks
This line seems to be the issue:
const busy = result.data.calendars[calendar].busy;
As far as I can tell, calendar is never defined. This should work instead:
const busy = result.data.calendars[context.GOOGLE_CALENDAR_ID].busy;
It looks like this line of the code is different between the "Google Calendar FreeBusy Queries" and "Recording VoiceMails" sections of the tutorial and needs to be updated in the latter code sample.

Fetch not working on react native when run on Expo from iphone

So it's actually been on and off the past few days, the fetch function for POST method (for login purposes) on my app would suddenly stop working when I'm not even making any changes to the code.
I spent hrs tracking down the bug the first time this happened but realized that the code is still running fine on Android simulator that I run from Android studio.
This problem only happens on my iphone device when I run the code via expo.
is there any sort of convention on how to tackle this issue?
I've been googling for a few days now but no one forum actually agreed on a solution, some works but says it's unstable and some just doesn't work.
I'm pretty new to expo, react native, and everything in general, so please enlighten me using "english" lol
EDIT: since I was asked about the code, here it is, I hope it helps:
export function login(user, callback){
var endpoint = "oauth/token";
const { username, password } = user;
//from https://scotch.io/tutorials/how-to-encode-and-decode-strings-with-base64-in-javascript
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}};
let header = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": ("Basic " + Base64.encode(username+":"+password))
};
let userData = {
"grant_type": "password",
"username": username,
"password": password
};
return fetchAPI(endpoint,'POST', header, userData)
.then((tokenJson) => {
alert("\nAccess Token:\n\n" + tokenJson.access_token + "");
callback(true, {exists : true, token : tokenJson.access_token}, null);
})
.catch((error) => {
alert(error);
callback(false, null, error);
});
}
And here's the fetchAPI function (a generic fetch function) called from that function:
export function fetchAPI(endpoint, method, header, data) {
let url = 'http://10.64.2.149:8081/' + endpoint;
let options = {
method: method,
headers: header,
body: stringify(data) //from qs-stringify package
};
return fetch(url, options)
.then(response => {
return response.json()
.then((json) => { ...//not relevant from this point on
The fetch 'POST' seems to always get stuck at response.json(), it just never resolves until it returns "network request failed". But as I said only happens sometimes when I run it on iphone via expo. It is fine on Android sim.
Thanks! :)

FB redirect issue with white page in iOS chrome

When I press the login button I get the facebook page where I have to give permission to use my facebook account.
After I give permission, it redirects to https://www.facebook.com/dialog/permissions.request and a blank page is shown. On Android the "window.FB.login" callback is called (see code below) where I can get the info and redirect the user but on Windows Phone it only shows that blank page. When I go to my facebook page, my site is registered in the app list. So the registration did work correctly.
This error has been caused due to unsafe loading of facebook js file.
For integrating Facebook app in your application you have to follow the steps instructed in Facebook app documentation.
var fbApi = {
init: function () {
$.getScript(document.location.protocol + '//connect.facebook.net/en_US/all.js', function () {
if (window.FB) {
window.FB.init({
appId: MY_APP_ID,
status: true,
cookie: true,
xfbml: false,
oauth: true,
channelUrl: 'http://www.yourdomain.com/channel.html'
});
}
});
},
login: function () {
/// <summary>
/// Login facebook button clicked
/// </summary>
log("login facebook button clicked");
if (window.FB) {
//Windows phone does not enter this method, Android and Iphone do
window.FB.login(function (response) {
if (response.status) {
log('it means the user has allowed to communicate with facebook');
fbAccessToken = response.authResponse.accessToken;
window.FB.api('/me', function (response) {
//get information of the facebook user.
loginService.subscribeSocialUser(response.id, response.first_name, response.last_name, fbAccessToken, "", "FaceBook", fbSucces, fbFail);
});
} else {
log('User cancelled login or did not fully authorize.');
}
},
{ scope: 'email'
});
}
}
};
channel URL is added so as to resolve any cross browser issues.
It should point to an html file which refers to the js as follows:
<script src="//connect.facebook.net/en_US/all.js"></script>
If once an error has been hit while initializing Facebook.js, you will not be able to login successfully.
You can load java script either synchronously or asynchronously.
(function(d, debug){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all" + (debug ? "/debug" : "") + ".js";
ref.parentNode.insertBefore(js, ref);
}(document, /*debug*/ false));

Resources