yam.platform.getLoginStatus invokes callback without response.user - javascript

When I call yam.platform.getLoginStatus right after logging in using yam.platform.login (shows the popup etc.) I get a different object passed to the callback than when the user is already logged in. Specifically, the 'user' field is missing on the LoginStatus response object, otherwise it looks the same as far as I can see.
I have the following controller for a 'login with yammer' area on my angular app:
function YammerLoginController($scope, $compile) {
$scope.isLoggedIn = false;
$scope.userName = "-";
$scope.login = function () {
yam.platform.login(function (response) {
if (response.authResponse) {
console.log("logged in");
}
refreshLoginStatus();
});
}
refreshLoginStatus(); // initialize values
function refreshLoginStatus() {
yam.getLoginStatus(function (response) {
console.dir(response);
if (response.authResponse) {
if (response.user) {
console.log("YammerLogin: Logged in as " + response.user.full_name);
console.dir(response);
$scope.$apply(function () {
$scope.isLoggedIn = true;
$scope.userName = response.user.full_name;
});
}
else {
console.log("WTF Yammer API!"); // THIS HAPPENS.
}
}
else {
console.log("YammerLogin: Not logged in.");
$('#loggedInView').popover("hide");
$scope.$apply(function () {
$scope.isLoggedIn = false;
$scope.userName = "-";
});
}
});
}
When the controller is created it already queries the current login status using the refreshLoginStatus function. If a yammer user is already logged in the app will display the user name and a logout button on the page (done with ng-show="isLoggedIn"). If the user is not logged in, a login button will be shown instead. When the user clicks on that login button, the $scope.login function will be called, invoking yam.platform.login and, if successful, calls refreshLoginStatus again in order to retrieve and set the user's name. In this scenario, the object returned from both, login and getLoginStatus do not contain the user information like in the 'user is already logged in' scenario. I tried calling the SDK-API again after some timeout, but apparently the response is cached - I always get the same. Only refreshing the whole page clears out the current response, querying the status again and receiving a 'complete' response object.
I thought it could be a scoping problem, but by now I'm not sure whether it's a problem in the SDK itself. :S
EDIT: I kind of found a solution, which however only gives me worse problems. Apparently the request is indeed cached. A refresh can be forced by using 'force refresh' on yam.platform.getLoginStatus(callback, [forceRefresh]). This, however gives me the following error on the browser console:
XMLHttpRequest cannot load
https://www.yammer.com/platform/login_status.json?client_id=2h4U2Hndg5kdWQ8xxxxxx.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:9000' is therefore not allowed
access.
Basically, the SDK fails to getLoginStatus, completely, and reports this back to my code as 'no connection'. I'm not sure what's worse... or, what am I doing wrong?

It appears that is just an inconsistency in the yam.platform.getLoginStatus API or the corresponding Yammer service called. If the user logs in, you get the user info, if he is alreaddy logged in, you don't get it. That is just weird but apparently can't be helped.
However, I solved this problem by simply always getting the user login data using a separate REST service call on /users/current.json once the session is authenticated (once I have the token from getLoginStatus).

Related

Can I alert the user from the route/middleware?

I am using the route to check if a token is valid or not. If it isn't I route the user to the log in page. I want to let the users know they're being logged out either as an alert or on the page.
What happens is a user clicks on Link A (to take them to another page on the website), the route calls a validate.js file:
route.js
var checkToken = require('../validate.js');
router.use(checkToken.checkToken);
This then calls the validate.js file which makes a HTTP call to check
if the token is valid, if it isn't it redirects the user to the Login
page:
validate.js
var checkToken = function(req, res, next) {
if (config.enableTokenValidation) {
var usersToken = req.user.token;
validateToken(receivedToken, req.requestId, function(err, response, body) {
if (err || response.statusCode != 200) {
console.log("Error, token is not valid");
res.redirect("/auth/logout/");
} else {
return next();
}
});
How can I send a message to the loginView.js file so that I can display the error in the front end (or create an alert)?
But as this happens in the middleware and it is other routes to other pages within the program that trigger the validation check, the login page doesn't make the check and therefore I can't get the response there to alert the user.
If there any way of achieving this using the way I'm going about it, or are there any other ways I can go about it?
Many Thanks
Instead of doing
res.redirect();
Why do not you send an error message like
res.status('401').send({error:'Invalid Token'});
Then you can take the necessary steps in the errorHandler() of the api call.
You can return an object that contains a method that fires an Alert message (or a change in your HTML, if you want to change the view). Then you use yourObject.method from the Frontend.

Facebook Javascript API sending two requests

In my application I have a function like this one:
getProfile = function() {
FB.api('/me', function(response) {
console.log(response);
});
return false;
};
Which requests the "me" object from the Facebook Graph API over JavaScript, and it works as expected when I attach it to the onClick event of a regular link or call it from the console directly, but when I try to call it from the Facebook log in button:
<fb:login-button onlogin="getProfile()">
Get Profile
</fb:login-button>
I get the expected response only if I am logged out of Facebook and subsequently log in through the dialog; if I click the button while I'm already logged in, I get this:
And if I push the response to the browser:
getProfile = function() {
FB.api('/me', function(response) {
console.log(response);
var
profile = document.getElementById('profile'),
p = document.createElement('p');
p.innerHTML = response.first_name;
profile.appendChild(p);
});
return false;
};
Of course I get two paragraphs with my name in them.
Can anyone spot what I'm doing wrong? So far my Googling has me convinced that this is related to the way the SDK handles log in events (firing on every page load) but I can't figure out how I'm supposed to account for that in the application code.
I believe the onlogin event fires when you load the page because you are logged into Facebook. Then, when your user clicks the button, it also triggers the event. If you're not logged in in the first place, then the onlogin event doesn't fire on load.
UPDATE: to avoid this, simply don't hook the getProfile to the onlogin event except inside an if statement based on the FB.getLoginStatus method http://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/ Simply put, if you're logged in, don't attach an onlogin event, otherwise do an FB.Event.subscribe http://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe/ on the onlogin event and your method will run whenever the user logs in through your XFBML-generated login button.
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
//print the response data into the paragraph here
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
FB.event.subscribe( 'auth.login', function(){
getProfile();
});
} else {
// the user isn't logged in to Facebook.
}
});

FB.logout() called without an access token

I'm trying to log out of a website i've created with Facebook integrated.
Logging in works fine, but when I want to log out Firebug consistently gives me this error:
FB.logout() called without an access token.
I'm using the Facebook JavaScript SDK, and the code I've got to logout looks like this:
$(document).ready($(function () {
$("#fblogout").click(facebooklogout);
}));
function facebooklogout() {
FB.logout(function (response) {
}
)};
This is the logout code specified at the Facebook Developers Documentation just with a button being assigned the method on document.ready
Before this code I have the FB.init() method, that all runs fine.
If anyone's got a solution as to why FB.logout doesn't have an access token, it'd be appreciated.
To logout from the application which uses facebook graph API, use this JavaScript on the logout page just after the <form> tag:
window.onload=function()
{
// initialize the library with your Facebook API key
FB.init({ apiKey: 'b65c1efa72f570xxxxxxxxxxxxxxxxx' });
//Fetch the status so that we can log out.
//You must have the login status before you can logout,
//and if you authenticated via oAuth (server side), this is necessary.
//If you logged in via the JavaScript SDK, you can simply call FB.logout()
//once the login status is fetched, call handleSessionResponse
FB.getLoginStatus(handleSessionResponse);
}
//handle a session response from any of the auth related calls
function handleSessionResponse(response) {
//if we dont have a session (which means the user has been logged out, redirect the user)
if (!response.session) {
window.location = "/mysite/Login.aspx";
return;
}
//if we do have a non-null response.session, call FB.logout(),
//the JS method will log the user out of Facebook and remove any authorization cookies
FB.logout(handleSessionResponse);
}
The code works and is live on my site.
I went for the less trivial solution:
function facebookLogout(){
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
FB.logout(function(response) {
// this part just clears the $_SESSION var
// replace with your own code
$.post("/logout").done(function() {
$('#status').html('<p>Logged out.</p>');
});
});
}
});
}
Figured it out after so many tries.
Generally response.authResponse.accessToken contains token. So, its error about the accessToken not being there.
Think logically, where does that response come from in your code? Out of nowhere.
So, we need to get that response object from a function and get this working.
I don't know how it worked for others, but this worked for me.
Just replace the code with this
function logout(){
FB.getLoginStatus(function(response) {
FB.logout(function(response){
console.log("Logged Out!");
window.location = "/";
});
});
}
What we do here is, get the login status if the user is logged in and get the corresponding response in return, which contains all the necessary tokens and data. Once this is fetched, the token is used to log out the user.
I've tried something like this:
function fbLogout(){
if(typeof FB.logout == 'function'){
if (FB.getAuthResponse()) {
FB.logout(function(response) { window.location.href = PROJECT_PATH + '/index/logout'; });
return;
}
};
window.location.href = PROJECT_PATH + '/index/logout';
return;
}
Should be something more like this. There was a change to the JS API where you have to use authResponse instead of just session.
//handle a session response from any of the auth related calls
function handleSessionResponse(response) {
//if we dont have a session (which means the user has been logged out, redirect the user)
if (!response.authResponse) {
return;
}
//if we do have a non-null response.session, call FB.logout(),
//the JS method will log the user out of Facebook and remove any authorization cookies
FB.logout(response.authResponse);
}
The error says that you don't have an access token, you have to check for one using the FB.getAccessToken() function.
If there is no access token the function returns null. See example below:
function facebooklogout() {
try {
if (FB.getAccessToken() != null) {
FB.logout(function(response) {
// user is now logged out from facebook do your post request or just redirect
window.location.replace(href);
});
} else {
// user is not logged in with facebook, maybe with something else
window.location.replace(href);
}
} catch (err) {
// any errors just logout
window.location.replace(href);
}
}
With Typescript this function do work fine ..
signOutFacebook(): void {
/*SIGN OUT USER FACEBOOK.*/
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
FB.logout(function (response) {
console.log("Logged Out!");
});
} else {
console.log("The person is not logged into your webpage or we are unable to tell. !");
}
});
}/*FINAL 'signOutFacebook()'. */

Confused by nature of JS SDK Facebook Events

I'm having a bit of trouble designing the user login/logout mechanism of my website that works with facebook.
The behavior of certain facebook events seems counter-intuitive:
'auth.login' fires on every page load when the user is logged in.
FB.getLoginStatus() fires on every page load, as I would expect
'auth.logout' fires only when the user actually logs out, and unlike 'auth.login,' auth.logout does not fire on every page load when the user is not logged in.
I want to build a system that detects whether or not the users session thinks that user is logged into facebook. If the user's session is set to believe they're logged into facebook, but they're actually not then perform an ajax call to the server and update the session. If the session and the facebook js sdk are in agreement over whether the user is logged in or not, do nothing. And if the user's session is unaware that user is logged into facebook but the js sdk says they are, update the server with an ajax call.
I want to create an application that syncs with the users current facebook login status. And I would like that application to login/logout (by executing an ajax call to my server to update their session) whenever they're facebook status changes. This is difficult since I can't seemto reliably detect when a user logs in or out of facebook.
One particular problem I have is when the user loads the page and they're logged into facebook, BOTH the auth.login event and the FB.getLoginStatus() events fire.
My ultimate question is, what combination of facebook-events or general strategy do i have to use to create such an application. A good example of what I'm going for is hulu.com's implementation of facebook login into their website. Thanks for reading this!
<script>
window.fbAsyncInit = function() {
FB.init({appId: '<?=$facebook_app_id?>',
status: true,
cookie: false,
xfbml: true});
FB.getLoginStatus(function(response) {
console.log('getLoginStatus');
console.log(response);
if(response.session){
if(window.module.Globals.prototype.oauth_uid != response.session.uid){
//authenticated user unknown to server, update server and set session
window.module.VCAuth.prototype.session_login();
}
}else{
if(window.module.Globals.prototype.oauth_uid){
//unauthenticated user with authenticated session, update server and unset session
window.module.VCAuth.prototype.session_logout();
}
}
});
FB.Event.subscribe('auth.login', function(response){
console.log('auth.login');
console.log(response);
});
FB.Event.subscribe('auth.logout', function(response){
console.log('auth.logout');
console.log('response');
});
};
(function() {
var e = document.createElement('script'); e.async = true;
e.src = document.location.protocol +
'//connect.facebook.net/en_US/all.js';
document.getElementById('fb-root').appendChild(e);
}());
</script>
I would recommend using the same callback for all methods. This way you get one authentication code path to worry about. Like this: (which is not that far off from the code you provided)
function authCallback(response) {
if(response && response.session){
if(window.module.Globals.prototype.oauth_uid != response.session.uid){
//authenticated user with invalid session
window.module.VCAuth.prototype.session_login();
}
}else{
if(window.module.Globals.prototype.oauth_uid){
//unauthenticated user with authenticated session
window.module.VCAuth.prototype.session_logout();
}
}
}
FB.getLoginStatus( authCallback );
FB.Event.subscribe('auth.login', authCallback);
FB.Event.subscribe('auth.logout', authCallback);
You said one main problem was:
BOTH the auth.login event and the FB.getLoginStatus() events fire.
Just make sure that session_logout() and session_login() set/unset the oauth_uid before making the async call to the server so that the next time the callback is called the correct state of the VCAuth is set.
Note: auth.logout is not fired every page load because auth.logout implies the user was logged in. It doesn't make sense to fire auth.logout if the user was never logged in right?
Hope this helps.

Facebook permissions in IE Causing infinite facebook loop

I am trying to get permissions for a facebook app I am making, but every time I try to run the app in IE8 I cannot get the permissions box to show up. I have tested the app in firefox and it can open fine, and get all the permissions fine (i dont ask for any special ones).
When I run the debugger in IE8 I see that once the program hits FB.getLoginStatus(function (response) { (see code below) it then moves into an infinite loop of code written by facebook.
I think the issue is because of how I am making the permissions call. I have a form that I use for a login that will call the permissions method once the user attempts to login to the site. Here is the form and button in the form I use:
<form id = "membershipInfo" method = "post" action = "Login.aspx">
<input type = "button" id = "submitInfo" class = "MemberInfo" value = "Take Me There!" onclick = "authorize(acceptPermissions, rejectPermissions)"/>
And here is the auth method I use:
function authorize(successCallback, failureCallback) {
FB.getLoginStatus(function (response) {
//****** DOES NOT MAKE IT PAST HERE *******//
if (response.session) {
// logged in and connected user, carry on
session = response.session;
//Set access token
accessToken = response.session.access_token;
//Call success callback
successCallback();
} else {
// no user session available, Lets ask for perms
FB.ui(
{
method: 'permissions.request',
perms: permissionString //(equals "" )
},
function (response) {
if (response && response.session != null) {
//Get session
session = response.session;
//Set access token
accessToken = response.session.access_token;
//Call success callback
successCallback();
} else {
//Call failure callback
failureCallback();
}
});
}
});
When the user accepts permissions they get moved into a success callback method which is here (never makes it this far):
function acceptPermissions() {
//Code done before moving on
$('#submitInfo').submit();
}
Anyone see any issues?
That looks like it should work to me, so probably a good opportunity to file a bug report with Facebook....
That said, I think you could clean up your code using FB.login instead http://developers.facebook.com/docs/reference/javascript/FB.login/
FB.login(function(response){
if(response.session){
// logged in and connected user, carry on
session = response.session;
//Set access token
accessToken = response.session.access_token;
//Call success callback
successCallback();
}
else{
failureCallback();
}
}, {perms: permissionString});
So here's a question: do you have Flash installed? IE8, being the way it is, may be trying to load the Flash-based XD, and then failing silently. If you install Flash (and/or put in a catch for that), does it work?

Categories