First of all: I'm aware that there's plenty of questions about the same topic, but none of them did the trick for me (I've already been like 3 days trying to get this working)...
I'm working on a Javascript mobile game which includes some FB functions (through the Javascript Facebook API). I'm having trouble while trying to really log out from Facebook to log in with another user: everytime I log out, I expect to call the log in function and prompt the FB login dialog where I can specify my e-mail and my password, but instead of this, Facebook logs in automatically with the last user without even asking me for anything... I'm using CocoonJS as the mobile platform and plain Javascript (no jQuery):
Log in function:
CocoonJS.Social.Facebook.init({
appId:<<MYAPPID>>,
channelUrl: "channel.html"
});
var socialService = CocoonJS.Social.Facebook.getSocialInterface();
socialService.login(function(loggedIn, error) {
if (error) {
console.error("login error: " + error.message);
}else if (loggedIn) {
console.log("login suceeded");
// Ask for extended permissions
CocoonJS.Social.Facebook.requestAdditionalPermissions("publish", "publish_actions",
function(response)
{
callback(response.error ? false : true);
}
);
CocoonJS.Social.Facebook.getLoginStatus(function(response) {
if (response.status === 'connected')
{
CocoonJS.Social.Facebook.api(
"/me",
function (response) {
if (response && !response.error) {
// Getting "me" returns the information of the "same" user!
console.log("User: "+response.first_name+" "+response.last_name);
}
}
);
}
});
}
});
Log out function:
CocoonJS.Social.Facebook.getLoginStatus(function(response) {
if (response.status === 'connected')
{
CocoonJS.Social.Facebook.logout(function(response) {
console.log("User logged out!");
});
}
});
The console log is thrown, so it seems that the user has actually logged out, but when I restart the game, a kind of "I'm doing something" screen appears for less than a second and the same user who logged out is logged in again (even throwing their personal information through calling "me")... I was expecting Facebook to ask me with which user I would like to log in to my app, but it doesn't...
I thing it has something to do with "session" or "cookies", but I don't know how to clear them through Javascript (and, as I'm using CocoonJS as the "browser", I have little control over it)... Any idea?
Thanks in advance for your time and effort! :)
CocoonJS uses native iOS and Android Facebook SDKs. The SDK itself takes care of the session storage, no cookies are used in CocoonJS.
Facebook SDK has two different methods to close the session:
close(): Closes the local in-memory session object, but does not clear the persisted token cache.
closeAndClearTokenInformation(): Closes the in-memory session, and clears any persisted cache related to the session
CocoonJS.Social.Facebook.logout calls internally to closeAndClearTokenInformation on Android and iOS. It erases all the cached tokens, so the next login starts from scratch.
Facebook SDK uses the Facebook Application to handle the login process if it's installed on the device, otherwise it fallbacks to a webview based login. The problem may be that you are testing on a device with the Facebook Application installed, so the SDK is able to get the logged in user from the Facebook App and doesn't need to ask for it again. If you logout from the Facebook Application or you test your app on a device with no Facebook App, Facebook will ask for a user and password.
Related
I'm registering users to my site via Facebook and have come across an issue on mobile. I'll start by saying i'm fairly new to the Facebook user login processes. The journey goes like so:
Firstly I call the fb.login function on click of a button to launch the facebook popup window for them to login like so:
jQuery(".welcome-cta-facebook span").on("click",function(){
FB.login(function(response) {
if (response.authResponse) {
getFbUserDetails();
} else {
console.log('User cancelled login or did not fully authorize.');
}
});
});
I then call the getFbUserDetails function once they have signed in and accepted the app like so:
function getFbUserDetails(){
FB.api(
'/me',
'GET',
{"fields":"id,name,picture{url},email"},
function(response) {
console.log(response);
fbParameters = "?facebookID=" + response.id + "&facebookName=" + response.name + "&facebookEmail=" + response.email + "&facebookProfilePictureURL=" + response.picture.url;
/* then send the fb parameters to my DB */
}
);
};
This journey works exactly as it should for desktop which is great but I encounter some problems with mobile which i'm unsure how to resolve:
if the user is not logged into their mobile browser I get the following error:
not logged in: You are not logged in. Please login and try again
if the user is logged in through their mobile browser I get the following error:
"URL Blocked: This redirect failed because the redirect URI is not
whitelisted in the app’s Client OAuth Settings. Make sure Client and
Web OAuth Login are on and add all your app domains as Valid OAuth
Redirect URIs."
Not sure why i'm seeing these errors if it works fine on desktop. How can I get a smooth journey for collecting someone's details on mobile? I am correct in using this approach? Worth noting I am NOT using a facebook login button.
Thanks and appreciate the help I can get!
You need to add all URI in whitelisted fied for you Facebook App
Facebook Developers -> Settings -> Advanced -> Security
In Security block you will see 'IP allowed server'
Add all URI in this field
I have a canvas facebook application which has both a web page and a designated mobile page.
The web page works fine and also when simulating the browser to mobile with the console everything works fine.
But, when I try to run the app from the facebook mobile app the canvas app loads (which is correct), but it does not login.
I am using the FB.login function.
login: function () {
var deferred = $q.defer();
FB.login(function (response) {
if (!response || response.error) {
deferred.reject('Error occured');
} else {
deferred.resolve(response);
}
}, {
scope: 'email, user_friends'
});
return deferred.promise;
},
and in the settings > advanced - I have the:
Client OAuth Login,Web OAuth Login, Embedded Browser OAuth Login,Valid OAuth redirect URIs and Login from Devices filled correctly.
but still from the facebook mobile app the canvas app does not preform the login.
I have been trying to get this to work all day.
and I cant find a solution anywhere.
I also cant debug the mobile facebook app.
any ideas how to approach this issue?
EDIT
Also looked at my Node server logs and I see that the FB.login is not even called.
EDIT 2
I ended up replacing the login with getLoginStatus which poses no problem to me since its a facebook canvas app... but the question still remains on how to do the login.
EDIT 3 11/26/2015
well so getLoginStatus did not completely solve my issue since it does not in fact log the user in so for the canvas games you probably need to login for the first entry if you need permissions... my solution was to add the login if the getLoginStatus returns not_autorized like so:
/**
* [getLoginStatus get the FB login status]
* #return {[type]} [description]
*/
getLoginStatus: function () {
var deferred = $q.defer();
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
deferred.resolve(response);
} else if (response.status === 'not_authorized') {
_fbFactory.login().then(function (fbLoginResponse) {
deferred.resolve(fbLoginResponse);
});
} else {
deferred.reject('Error occured');
}
});
return deferred.promise;
},
But wait, there is more... the FB.login function will not work well on mobile canvas games (not sure if its just not triggered or the browsers blog the popups or both). anyway you need to actively call it via button... so for mobile canvas games I had to add a start playing button and then the login does work..
EDIT 4 (Final)
eventually I noticed that FB.login() does not get triggered unless its an external event that triggers it, so I had to make a change for Mobile canvas where if the getLoginStatus doesnt return connected then I show a login button which does the login... the rest stayed the same.
what I did for mobile was similar to the accepted answer only to suit my needs...
I hope this helps someone besides me...
Make sure you're calling FB.login() with an event triggered by the user, such as an onclick on a button, as browsers can block potentially unsafe/dangerous javascript that's called directly. This is an extra layer of security for the end-user. There's 2 ways to create a login button:
Generate a login button with facebooks login button generator:
https://developers.facebook.com/docs/facebook-login/web/login-button
The generated login button will look similar to this:
<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>
Create your own html and use an onclick event to call FB.init():
<button onclick="FB.init()">Login</button>
Notes from the Facebook developers website:
As noted in the reference docs for this function, it results in a
popup window showing the Login dialog, and therefore should only be
invoked as a result of someone clicking an HTML button (so that the
popup isn't blocked by browsers).
https://developers.facebook.com/docs/facebook-login/web
Also, FB.getLoginStatus is the correct first step in logging in to check whether your user is logged into facebook and into your app.
There are a few steps that you will need to follow to integrate
Facebook Login into your web application, most of which are included
in the quickstart example at the top of this page. At a high level
those are:
Checking the login status to see if someone's already logged into your app. During this step, you also should check to see if someone
has previously logged into your app, but is not currently logged in.
If they are not logged in, invoke the login dialog and ask for a set of data permissions.
Verify their identity.
Store the resulting access token.
Make API calls.
Log out.
I see that your game doesn't require a login anymore, but maybe others will find this answer useful. :)
UPDATE:
In the end, I ended up imlementing using apache cordova/phonegap via Eclipse for android and xcode for iOS. This is the only solution that works on my preferred set up.
Link to download the plugin and documentation: https://github.com/phonegap/phonegap-facebook-plugin
Previous post:
I would like to implement facebook login into my hybrid apps. I already did few research in facebook documentation but I haven't found anything that works. If you can provide me some tips, that would be very helpful. I will reward a bounty for someone who can tell me how to do it.
I don't want to go through Phonegap/cordova and other framework since it would need me a lot of time to study those framework.
Hybrid apps - like native apps, run on the device, and are written with web technologies (HTML5, CSS and JavaScript). Hybrid apps run inside a native container, and leverage the device’s browser engine (but not the browser) to render the HTML and process the JavaScript locally. A web-to-native abstraction layer enables access to device capabilities that are not accessible in Mobile Web applications, such as the accelerometer, camera and local storage.
If anyone has any solution and willing to help, please let me know.
I've tried Javascript SDK but no luck.
Code:
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : 'xxxx', // App ID
channelUrl : '//xxxx/channel.html', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Here we subscribe to the auth.authResponseChange JavaScript event. This event is fired
// for any authentication related change, such as login, logout or session refresh. This means that
// whenever someone who was previously logged out tries to log in again, the correct case below
// will be handled.
FB.Event.subscribe('auth.authResponseChange', function(response) {
// Here we specify what we do with the response anytime this event occurs.
if (response.status === 'connected') {
// The response object is returned with a status field that lets the app know the current
// login status of the person. In this case, we're handling the situation where they
// have logged in to the app.
testAPI();
} else if (response.status === 'not_authorized') {
// In this case, the person is logged into Facebook, but not into the app, so we call
// FB.login() to prompt them to do so.
// In real-life usage, you wouldn't want to immediately prompt someone to login
// like this, for two reasons:
// (1) JavaScript created popup windows are blocked by most browsers unless they
// result from direct interaction from people using the app (such as a mouse click)
// (2) it is a bad experience to be continually prompted to login upon page load.
FB.login();
} else {
// In this case, the person is not logged into Facebook, so we call the login()
// function to prompt them to do so. Note that at this stage there is no indication
// of whether they are logged into the app. If they aren't then they'll see the Login
// dialog right after they log in to Facebook.
// The same caveats as above apply to the FB.login() call here.
FB.login();
}
});
};
// Load the SDK asynchronously
(function(d){
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.js"; */
js.src="https://connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
// Here we run a very simple test of the Graph API after login is successful.
// This testAPI() function is only called in those cases.
function testAPI() {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Good to see you, ' + response.name + '.');
});
}
</script>
<!--
Below we include the Login Button social plugin. This button uses the JavaScript SDK to
present a graphical Login button that triggers the FB.login() function when clicked.
Learn more about options for the login button plugin:
/docs/reference/plugins/login/ -->
<!-- <fb:login-button show-faces="true" width="200" max-rows="1"></fb:login-button> -->
<!-- End script of Facebook Login -->
Are you currently testing it from your local computer or hosting the HTML on a server?
if on a server - what is your domain?
update it on the app domains (see image)
update it on section "Website with Facebook Login"
for testing the issue, remove FB.api call from testAPI(). just put an alert.
test it from a standard browser. If it works - nothing is wrong with your FB definition.
Instead of FB.Event.subscribe
use FB.getLoginStatus
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
// the user is logged in and has authenticated your
// app, and response.authResponse supplies
// the user's ID, a valid access token, a signed
// request, and the time the access token
// and signed request each expire
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
FB.api('/me', function(response) {
console.log(response);
});
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
} else {
// the user isn't logged in to Facebook.
}
});
Reference link: https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/
I stumbled across a different solution which is working really well for me, and even better, no native code libraries! The trick here is to bypass the Facebook JavaScript SDK library and use the Facebook REST api endpoints directly.
I am using OpenFB javascript library (https://github.com/ccoenraets/OpenFB) to make this job easier, rather than write the calls all myself, but you can do it either way. I've outlined the steps on how to get it to work below.
1) Create a Facebook app and update the URL settings under Basic and Advanced to allow callbacks using facebook or your local urls. Then copy the Facebook ID ready for the next step
2) If you haven't already, download and install Cordova to put the tools in your command line. Then navigate to your Sites folder and run the following commands to create the project and add your platforms:
cordova create your-project-name
cordova platform add ios
cordova platform add android
3) Now we need to add a Cordova plugin to handle pop-up windows from facebook logins. To add a plugin use the command:
cordova plugin add org.apache.cordova.inappbrowser
4) Now we just need to download and configure OpenFB inside our new Cordova project. For this example we will just use the test page they provide, so download it from the OpenFB Github page and extract the files into your cordova project /www/ folder. After this open the index.html and edit the following line with your Facebook App ID from step 1:
openFB.init({appId: 'YOUR_FB_APP_ID'});
5) You should now be able to run the example and login using your local browser setup.
6) To test on iOS simulator you will need xCode installed then run the command:
cordova emulate ios
To test on an android emulator you will need the Android SDK installed and then run the command:
cordova emulate android
To test on an iOS device connected with a cable, run following command:
cordova run ios
To test on an Android device connected with a cable, run following command:
cordova run android
In my application, I implemented Google signout using jsapi.
I used the url https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=xxxxxx to connect to Google and then https://www.googleapis.com/plus/v1/people/xxxxxx to get user data from google profile.
Now I need to signout the user from Google while clicking a button from my application. How can I implement this in JavaScript, or at least it must ask the Google login page every time the user signs in.
I have tried approval_prompt=force, but seems not to be working.
Overview of OAuth: Is the User Who He/She Says He/She is?:
I'm not sure if you used OAuth to login to Stack Overflow, like the "Login with Google" option, but when you use this feature, Stack Overflow is simply asking Google if it knows who you are:
"Yo Google, this Vinesh fella claims that vinesh.e#gmail.com is him, is that true?"
If you're logged in already, Google will say YES. If not, Google will say:
"Hang on a sec Stack Overflow, I'll authenticate this fella and if he can enter the right password for his Google account, then it's him".
When you enter your Google password, Google then tells Stack Overflow you are who you say you are, and Stack Overflow logs you in.
When you logout of your app, you're logging out of your app:
Here's where developers new to OAuth sometimes get a little confused... Google and Stack Overflow, Assembla, Vinesh's-very-cool-slick-webapp, are all different entities, and Google knows nothing about your account on Vinesh's cool webapp, and vice versa, aside from what's exposed via the API you're using to access profile information.
When your user logs out, he or she isn't logging out of Google, he/she is logging out of your app, or Stack Overflow, or Assembla, or whatever web application used Google OAuth to authenticate the user.
In fact, I can log out of all of my Google accounts and still be logged into Stack Overflow. Once your app knows who the user is, that person can log out of Google. Google is no longer needed.
With that said, what you're asking to do is log the user out of a service that really doesn't belong to you. Think about it like this: As a user, how annoyed do you think I would be if I logged into 5 different services with my Google account, then the first time I logged out of one of them, I have to login to my Gmail account again because that app developer decided that, when I log out of his application, I should also be logged out of Google? That's going to get old really fast. In short, you really don't want to do this...
Yeh yeh, whatever, I still want to log the user out Of Google, just tell me how do I do this?
With that said, if you still do want to log a user out of Google, and realize that you may very well be disrupting their workflow, you could dynamically build the logout url from one of their Google services logout button, and then invoke that using an img element or a script tag:
<script type="text/javascript"
src="https://mail.google.com/mail/u/0/?logout&hl=en" />
OR
<img src="https://mail.google.com/mail/u/0/?logout&hl=en" />
OR
window.location = "https://mail.google.com/mail/u/0/?logout&hl=en";
If you redirect your user to the logout page, or invoke it from an element that isn't cross-domain restricted, the user will be logged out of Google.
Note that this does not necessarily mean the user will be logged out of your application, only Google. :)
Summary:
What's important for you to keep in mind is that, when you logout of your app, you don't need to make the user re-enter a password. That's the whole point! It authenticates against Google so the user doesn't have to enter his or her password over and over and over again in each web application he or she uses. It takes some getting used to, but know that, as long as the user is logged into Google, your app doesn't need to worry about whether or not the user is who he/she says he/she is.
I have the same implementation in a project as you do, using the Google Profile information with OAuth. I tried the very same thing you're looking to try, and it really started making people angry when they had to login to Google over and over again, so we stopped logging them out of Google. :)
You can log out and redirect to your site:
var logout = function() {
document.location.href = "https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://www.example.com";
}
For me, it works (java - android)
void RevokeAcess()
{
try{
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/revoke?token="+ACCESS_TOKEN);
org.apache.http.HttpResponse response = client.execute(post);
}
catch(IOException e)
{
}
CookieManager.getInstance().removeAllCookie(); // this is clear the cookies which tends to same user in android web view
}
You have to call this function in AsyncTask in android
To logout from the app only but not the Gmail:
window.gapi.load('auth2', () => {
window.gapi.auth2
.init({
client_id:
'<Your client id configired on google console>'
})
.then(() => {
window.gapi.auth2
.getAuthInstance()
.signOut()
.then(function() {
console.log('User signed out.');
});
});
});
I'm using above in my ReactJs code.
You can simply Create a logout button and add this link to it and it will utimately log you out from the app and will redirect to your desired site:
https://appengine.google.com/_ah/logout?continue=http://www.YOURSITE.com
just toggle YOURSITE with your website
This works to sign the user out of the application, but not Google.
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
});
Source: https://developers.google.com/identity/sign-in/web/sign-in
Ouath just makes the Google instance null, hence it you out of Google. Now that's how the architecture is made. Logging out of Google, if you Logout of your app is a dirty work, but can't help if the requirement stipulates the same. Hence add the following to your signOut() function. My project was an Angular 6 app:
document.location.href = "https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:4200";
Here localhost:4200 is the URL of my app. If your login page is xyz.com then input that.
this code will work to sign out
<script>
function signOut()
{
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
auth2.disconnect();
});
auth2.disconnect();
}
</script>
I hope we can achieve this by storing the token in session while logging in and access the token when he clicked on logout.
String _accessToken=(String)session.getAttribute("ACCESS_TOKEN");
if(_accessToken!=null)
{
StringBuffer path=httpRequest.getRequestURL();
reDirectPage="https://www.google.com/accounts/Logout?
continue=https://appengine.google.com/_ah/logout?
continue="+path;
}
response.sendRedirect(reDirectPage);
It looks like Google recently broke something with their revoke stuff (it's started returning 400 errors for us). You now have to call
auth2.disconnect();
In our case we then have to wait a couple of seconds for the disconnect call to complete otherwise the sign-in code will re-authorise before it's done. It'd be good if google returned a promise from the disconnect method.
If any one want it in Java, Here is my Answer, For this you have to call Another Thread.
1. Try this code, if you are using onSignIn() function
2.
<script src="https://apis.google.com/js/platform.js?onload=onLoad" async defer></script>
<script>
function signOut() {
onLoad();
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
if(auth2.isSignedIn)
{
auth2.isSignedIn.set(false);
}
});
}
function onLoad() {
gapi.load('auth2', function() {
gapi.auth2.init();
});
}
</script>
I'm writing a webapp where users will need to login with Facebook (a Facebookless login does not make sense in the context of the app). Ideally, after their initial visit, when a user visits /index, my webapp sees a cookie it deposited earlier, and seamlessly logs the user in automatically and goes to the application (/app).
My problem arises when the user logs out of Facebook, and returns to my app. Since their cookie on my domain will still be present, and their oauth_token will still be valid (they are for 60 days now), I can still log the user in automatically, and the app will work as expected.
To me, it doesn't seem right that the app remains signed in with their Facebook account even when they are not signed in to Facebook. I played around on Stackoverflow itself; it allows this behaviour as well. Are my worries misplaced, or is there a recommended way to see if a user is signed into Facebook when they first request /index from my server.
In my opinion, I don't think your app should remain signed in while the user has already signed out of Facebook.
One scenario where this may not be desirable is: what if I am using your app from a public computer. After I logged out of Facebook, your app still "remembers" me. And now anyone who uses this computer will assume my Facebook identity inside your app.
I think the problem here is that you set your own cookie to remember the user's Facebook login status. Obviously, when user signes out of Facebook itself, your cookie is not cleared. So at this point your cookie is out of sync with Facebook status.
I recommend that you don't use your own cookie for the purpose of remembering user's Facebook login status. Always rely on Facebook itself for this purpose.
The general strategy is, whenever user comes to your app, you should check the Facebook login status by using the mechanism provided by Facebook. This way, your app will be in syn with Facebook in terms of user's login status.
I personally use this piece of code to call Facebook Javascript API for the purpose of user login:
/*
* Init code for Facebook connect
*/
window.fbAsyncInit = function() {
FB.init({
appId : FACEBOOK_APP_ID, // App ID
channelUrl : CHANNEL_URL, // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true, // parse XFBML
oauth : true
});
// check facebook login status
FB.getLoginStatus(function(response) {
console.log("FB login status: " + response.status);
if (response.status === 'connected') {
showWelcome(); //display welcome message
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook, but not connected to the app
showFbLogin(); //display Facebook Login button
} else {
// the user isn't even logged in to Facebook.
showFbLogin(); //display Facebook Login button
}
});
// subscribe to facebook events
FB.Event.subscribe('auth.authResponseChange', function(response) {
fbAuthResponseChanged(response);
});
};