Here is my code:
function googleLogOut() {
debugAlert("googleLogOut:Begin");
GoogleAuth.disconnect();
GoogleAuth.signOut().then(function () {
debugAlert("googleLogOut:Logout Completed, current login status = " + GoogleAuth.isSignedIn.get());
userNotLoggedIn();
debugAlert("googleLogOut:Exit");
});
}
According to my understanding, the disconnect revokes the authorization which the currently signed-in user has granted to my application and the signOut should log the user out of his Google account, basically backing out the OAuth signin which the user went through originally in order to gain access to my application.
However, immediately after GoogleAuth.signOut(), GoogleAuth.isSignedIn.get() evaluates to true - see alert dialog image:
Alert Dialog
Actually, as it turns out, the user is still logged in to his Google account so technically isSignedIn.get() is returning the correct value. I confirmed this by opening a new browser tab and going to gmail - clearly I was still logged in. More to the point though, what this code does is revoke all of the permissions which the user has granted to my application - that is the essence of this logout function. To test this -
GoogleAuth.currentUser.get().hasGrantedScopes(SCOPE) == false
So the compound test for whether a Google account is logged in to my application is:
GoogleAuth.isSignedIn.get() == true && GoogleAuth.currentUser.get().hasGrantedScopes(SCOPE) == true
Here's the modified logout function. (Same functionality, just modified the debug statements to show the revocation of the scopes privileges.)
function googleLogOut() {
debugAlert("googleLogOut:Begin");
GoogleAuth.disconnect();
GoogleAuth.signOut().then(function () {
debugAlert("googleLogOut:Logout Completed, current login status = " + GoogleAuth.isSignedIn.get());
if (GoogleAuth.isSignedIn.get()) {
debugAlert("googleLogOut:Logout Completed, current SCOPE status = " + GoogleAuth.currentUser.get().hasGrantedScopes(SCOPE));
}
userNotLoggedIn();
debugAlert("googleLogOut:Exit");
});
}
Here's a completely different way to do this. I found this to be much more reliable.
logoutWindow = window.open("https://accounts.google.com/SignOutOptions", "_blank", "toolbar=no,width=600,height=400");
I just open a window to Google's account management page. When the user signs out, they are signed out from my application as well.
As the icing on the cake, when I trap the user logged out event in my application I close the window - if the user is logging out through a window which my application has invoked:
try {
logoutWindow.close();
}
catch (err) {
// nothing...
}
Use GoogleAuth.isSignedIn.listen(listener) - when your listener is called the state of GoogleAuth objects has already been updated.
Related
So I recently had acceptance criteria for a site I was building that went as such:
After a user logs in to the site in any tab if they navigate to the site in a new tab they must already be logged in
When a user logs out of any tab they must log out of all tabs immediately
A user can refresh the page and stay logged in
Once all tabs are closed the user is logged out and must log back in
I didn't have access to change the server code (so this had to be done on the client)
I found this Question/Answer which was really helpful
When looking through this I had to rule out cookies because outside of doing a request to the server tab A will no know that tab B had changed the cookie
So I took some parts of the answer from the question above and started using local-storage and added an event to check for if the 'logged-in' state was changed which allowed me to log out in one tab and immediately log out in another without using setInterval to continuously check! Yay
But then I still had the issue of once all tabs were closed if you opened a new tab and navigated to the site you were still logged in.
I tried some possible solutions like having a counter of the tabs that has a session open, decrement and increment on tab close/open (using window.onbeforeunload). ISSUE: refresh of the site when there is only one tab active would log you out. Everything I could think of had an edge case where it didnt work.
local-storage + session-storage!
I would store the value logged-in in both the local-storage and the session storage, when a window was loaded (either a new tab or a refresh of the existing one) it would check local-storage for the 'logged-in' value and if it was not there it would check session-storage!
Basically I am using session-storage to handle the refresh of a page and local-storage to handle multiple tabs. Each time a window/tab is unloaded (closed or refreshed) I delete the local-storage 'logged-in' and when I come back into the page if it is in session-storage but not in local-storage I put it back into local-storage from the session-storage and continue as an authenticated user
Here is the code for this:
On login:
localStorage.setItem('logged-in', true);
sessionStorage.setItem('logged-in', true);
In my base component:
window.onbeforeunload = (event) => {
localStorage.removeItem('logged-in');
}
let loggedIn = localStorage.getItem('logged-in');
let sessionLoggedIn = sessionStorage.getItem('logged-in');
if(!loggedIn) {
if(sessionLoggedIn) {
localStorage.setItem('logged-in', JSON.parse(sessionLoggedIn));
//go to authenticated space
window.location.href = '/authenticated';
} else {
//go to login
window.location.href = '/login';
}
} else {
//go to authenticated space
window.location.href = '/authenticated';
}
window.addEventListener('storage', (event) => {
if (event.key == 'logout' && event.newValue) {
sessionStorage.removeItem('logged-in');
localStorage.removeItem('logout');
window.location.href = '/login';
}
});
On logout
localStorage.setItem('logout', true)
Hope this helps some of you if you ever find yourself in a similar situation
I'm currently building an app which requires to login first. Login page is called using
function onDeviceReady() {
navigator.splashscreen.hide();
window.open("http:website_login_link", "_blank");
}
since that website's login page needs to be opened first when the app is launched (because only certain people are allowed to login). After login, the user is brought to the website, but I want the user be able to see other features of the app. Thus, I want to redirect to a specific page after the user is logged in. I want to set isLoggenIn = true after the user has been logged in. And then call
if (isLoggedIn == true){
window.location("home.component.html"); // welcome page
}
But I don't know how to detect when I should set isLoggenIn = true, since I'm not storing credentials manually. So, how and when can I set isLoggenIn = true ?
window.location = "http:website_login_link";
Two method
1. window.location = "Your website"
2. location.href="Your website"
Im implementing auth using this and am currently showing a loading icon in React when a user clicks the button to sign in and the auth2 account selection/login window shows.
However if a user closes the window, there doesnt seem to be any event fired i.e the signIn() function which returns a promise never resolves, I would have thought google would return an error for this promise if the window is closed. As a result there is no way for me to stop showing the loader icon and reshow the login menu.
I was wondering if anyone had a solution for this?
I try to modifiy my code that call Google OAuth 2.0 window.
You only have to add extra AJAX method that cover what is Google OAuth error result.
gapi.auth2.getAuthInstance().signIn()
Change it to this one,
gapi.auth2.getAuthInstance().signIn().then(function(response){
//If Google OAuth 2 works fine
console.log(response);
}, function(error){
//If Google OAuth 2 occured error
console.log(error);
if(error.error === 'popup_closed_by_user'){
alert('Oh Dude, Why you close authentication user window...!');
}
});
That's it...
For more detail about Google OAuth 2.0 information, you can visit this link.
https://developers.google.com/api-client-library/javascript/samples/samples#authorizing-and-making-authorized-requests
Sample code on JavaScript:
https://github.com/google/google-api-javascript-client/blob/master/samples/authSample.html
Although the API provides a mechanism for detecting when the user clicks the Deny button, there is not a built-in way for detecting that the user abruptly closed the popup window (or exited their web browser, shut down their computer, and so on). The Deny condition is provided in case you want to re-prompt the user with reduced scopes (e.g. you requested "email" but only need profile and will let the user proceed without giving you their email).
If the response from the sign-in callback contains the error, access_denied, it indicates the user clicked the deny button:
function onSignInCallback(authResult) {
if (authResult['error'] && authResult['error'] == 'access_denied') {
// User explicitly denied this application's requested scopes
}
}
You should be able to implement sign-in without detecting whether the window was closed; this is demonstrated in virtually all of the Google+ sample apps. In short, you should avoid using a spinner as you're doing and instead should hide authenticated UI until the user has successfully signed in.
It's not recommended you do this, but to implement detection of the pop-up closing, you could do something like override the global window.open call, then detect in window.unload or poll whether the window was closed without the user authenticating:
var lastOpenedWindow = undefined;
window.open = function (open) {
return function (url, name, features) {
// set name if missing here
name = name || "default_window_name";
lastOpenedWindow = open.call(window, url, name, features);
return lastOpenedWindow;
};
}(window.open);
var intervalHandle = undefined;
function detectClose() {
intervalHandle = setInterval(function(){
if (lastOpenedWindow && lastOpenedWindow.closed) {
// TODO: check user was !authenticated
console.log("Why did the window close without auth?");
window.clearInterval(intervalHandle);
}
}, 500);
}
Note that as I've implemented it, this mechanism is unreliable and subject to race conditions.
My page /login.php displays the signin button and signs you in. So far I have managed to:
Include relevant code in common files so that G+ signin code is present in all pages
Moved stuff from the button element itself to tags in the header
Instead of keeping any significant logic in my signinCallback, I attached a callback function that is called on each page load, like this:
po.src = 'https://apis.google.com/js/client:plusone.js?onload=OnLoadCallback';
I then made that function look like this:
function OnLoadCallback(){
var sessionParams = {
'client_id': 'myapp-id-here',
'session_state': null
}
gapi.auth.checkSessionState(sessionParams, function(stateMatched){
if(stateMatched === true){
console.log("You do not seem to be logged in!");
}else{
console.log("You should be logged in!");
// Trigger request to get the email address.
gapi.client.load('plus','v1', loadProfile);
if(window.location.pathname === '/login.php'){
toggleElement('signin-button');
window.location = "/";
}
}
});
}
I found this bit of code regarding the session state in some article but I'm not sure it works as it's supposed to. In Chrome it seems more or less OK but in FF, when I first tried it, it should give me "not logged" in my console. Since I was logged in FF with my google account (but not in my app!), it seemed to recognize me as logged in, or at least my session was anything but the null (as stated in the code).
So, what should I use instead of "null" when it comes to determining session state?
I'm building a facebook connect app to publish content to user's streams. In order to do that, I need to get extended publish_stream permission from the users. I'm using the function code to do so.
Check connection status
<input type="button" onclick="statusSubmit('Permission to publish : ');" value="Check connection status" />
<script type="text/javascript">
function statusSubmit(status)
{
facebook_prompt_permission('publish_stream', function(accepted)
{
if(accepted) {
// User (already) has permission
alert(status + 'already granted');
}
else
{
// User does not have permission
alert(status + ' not granted');
}
});
}
function facebook_prompt_permission(permission, callbackFunc)
{
// Check if user has permission, if not invoke dialog.
FB.ensureInit(function() {
FB.Connect.requireSession(function(){
//check is user already granted for this permission or not
FB.Facebook.apiClient.users_hasAppPermission(permission,
function(result) {
// prompt offline permission
if (result == 0) {
// render the permission dialog
FB.Connect.showPermissionDialog(permission,
function(result){
if (null == result)
alert('no permissons granted');
else
alert('permissions ' + result);
}, true, null);
} else {
// permission already granted.
callbackFunc(true);
}
});
});
});
}
</script>
After the permissions dialog is displayed and the user grants the permissions, there is a redirect my current page on my local development machine. I cannot seem to control this redirect behaviour through my settings. I have tried changing the "Post-Authorize Callback URL" to a publicly visible page, but it does not get called. Is there something I'm missing? I would like to either
Get the post-authorize callback URL to something that works OR
Even better if there is no redirection after the user grants
permissions. This option would be the best.
Thank you for any suggestions.
abronte, Thank you for your suggestion. I actually figured out that the path to xd_receiver.htm was incorrect, which was causing all the weird behavior. When I corrected that, things were OK. But the FB Javascript API is very flaky, we decided not to use it as the behavior is erratic. We will be switching to a server based solution in the future.
I believe that the post-authorize callback url that is set in the application settings only deals with within facebook canvas sort of stuff. What url is called after you authorize the app in facebook.
What I think the best solution is (and this is what i do) is to manually redirect the user after the extended permissions prompt is completed.
window.location = '/path/to/something';