I am getting an error message when attempting to use the Facebook API.
When I have Client OAuth Login enabled, Web OAuth Login enabled and a valid Oauth redirect URI set to http://localhost:8000/ the error I get is this when trying to log into Facebook with the correct App ID:
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.
Is there a particular setting or thing I have to put in code to get this to work correctly?
This is the code I've got:
$(window).load(function() {
if (window.cordova.platformId == "browser") {
facebookConnectPlugin.browserInit(MYAPPIDHERE);
}
});
And this:
facebookConnectPlugin.login(["user_likes"],
function(response) {
likes();
},
function(response) {
likes();
});
}
EDIT:
Added pictures of what is in the Facebook App, as well as the URL I am navigating from.
You might want to check for HTTP calls made by facebookConnectPlugin and see if the redirect_uri in the query string matches the one you have in your Facebook App settings as a valid redirect URI.
It might look something like this:
https://www.facebook.com/dialog/oauth?client_id={FB_APP_ID}&redirect_uri=http://localhost:8000/
EDIT:
There seems to be an issue with the redirect_url=http://static.ak.fbcdn.net/connect/xd_proxy.php#cb=f11b73fd18e512c# being used by facebookConnectPlugin. I checked the javascript code and it is using phonegap/plugin/facebookConnectPlugin/fbsdk.js, which seems to be the culprit.
When I used direct loading of FB SDK, it uses a different redirect_url=http://staticxx.facebook.com/connect/xd_arbiter/r/RYqXvcNXPI-.js?version=42. Replacing the previous redirect_url with this one solved the issue for me. It is possible that phonegap's fbsdk.js uses an outdated script.
Bottomline: It would be better to load FB SDK directly, as mentioned here. And according to FB docs, it would look like this:
<script>
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
Lastly, to enable debug logs, replace //connect.facebook.net/en_US/sdk.js to //connect.facebook.net/en_US/sdk/debug.js.
The Javascript API wont work on PhoneGap for the login.
Use this cordova plugin instead.
https://github.com/Wizcorp/phonegap-facebook-plugin
It is impossible for Facebook to redirect to a local URL. What will happen is that you redirect a user to Facebook, they login, Facebook validates this and sends them back to you. Facebook sends them to the URL you provide. The URL http://localhost:8000 is a shorthand for: connect to port 8000 on your own machine. At the point where Facebook does the redirect, localhost refers back to Facebook, not you anymore. Apparently, Facebook has blacklisted that stuff - probably for security reasons.
What you need is a public URL that Facebook can redirect to. Maybe this helps?
Try these things:
set the URI to http://localhost/ (no port)
put a callback at the redirectURI with a corresponding callback function. i.e., http://localhost/loginCallback
Report back with any errors, I have a feeling the 1st way will work.
Related
When calling FB.getLoginStatus using a valid Facebook App the response status is always unknown. Exact response is {authResponse: undefined, status: "unknown"}.
<html>
<body>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function(){
FB.init({ appId:'1484134468466778', status:true, cookie:true, xfbml:true});
FB.getLoginStatus(function(response){
console.log(response);
});
};
(function(d){
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
d.getElementsByTagName('head')[0].appendChild(js);
}(document));
</script>
</body>
</html>
Example URL:
http://media.tuentifotos.com/simple_test.html
Here a screenshot of the Facebook App Settings.
This was happening for me in Chrome, and was because Chrome was configured to block third-party cookies and data.
Once I made that configuration change, FaceBook is able to log me into my app without a problem.
Chrome Settings
Show advanced settings...
Privacy
Content settings...
uncheck Block third-party cookies and site data
I too faced this problem in Chrome. However, in Firefox it worked as expected with the status returned as connected when the user had logged in previously.
I found a clue about this from an answer to the similar question here.
The root cause of this issue is, on FB.logout(), Chrome is not removing the cookie fblo_<your-app-id> which is somehow affecting FB.getLoginStatus() function to return unknown
Fix: On calling FB.logout(), you may programmatically delete the cookie fblo_<your-app-id>
FB.logout(function(response) {
deleteCookie("fblo_" + fbAppId); // fblo_yourFBAppId. example: fblo_444499089231295
});
function deleteCookie(name) {
document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
When I checked, the status is showing "not_authorized" and that's fine, since I've not authorized the app yet.
To complete the flow, you should add the FB.login whenever user id is not authorized or not logged-in to facebook:
window.fbAsyncInit = function(){
FB.init({ appId:'{APP-ID}', status:true, cookie:true, xfbml:true});
FB.getLoginStatus(function(response){
if (response.status === 'connected') {
//proceed
} else if (response.status === 'not_authorized') {
login();
} else {
login();
}
});
};
function login(){
FB.login(function(response) {
if (response.authResponse) {
// proceed
} else {
// not auth / cancelled the login!
}
});
}
For me this meant "on my login page" I needed to specify cookies.
window.fbAsyncInit = function() {
FB.init({
version: 'v2.8',
cookie : true,
});
};
But don't ask me why this was the case. It also fixed it needing to click twice on the login button to actually login, and doesn't even require an appId, seemingly, FWIW...
The final answer
Ok so I think I've finally figured this damn issue out.
What you need to know:
1) You authenticate with Facebook via an app ID. This sets various cookies, where your app ID is tagged on the end:
fblo_000000000000
fbm_000000000000
fbsr_000000000000
2) If you delete these cookies, you're still authenticated to facebook as a regular user (unless you log out completely). And on Facebook's servers they still know you are authorized on this app.
So when you run FB.getLoginStatus() again it will just recreate them and put them back again. This is not what your user expects. This is bad. They clicked 'Log out'.
3) The docs explicitly say this:
The user is either not logged into Facebook or explicitly logged out of your application so it doesn't attempt to connect to Facebook and thus, we don't know if they've authenticated your application or not. (unknown)
So they don't even TRY to check if this cookie is set. That's why you get null or undefined. So the fblo cookie is considered like an 'opt-out'. You're NOT ACTUALLY LOGGED OUT by what any regular person would consider being logged out as to mean. There's just a cookie saying you are! Of course if the user logs back in with the login button then the cookie will be deleted, which is what you and your user wants.
Therefore I believe the only thing that makes sense to do (if you truly need to know the user's status) is to:
Manually check the existance of fblo_<APPID> cookie before you run FB.getLoginStatus.
If the cookie doesn't exist then do nothing and run your normal flow.
If the cookie does exist you have several options :
1) Option 1
Do absolutely nothing. You now understand the issue, you understand not to delete the cookie and perhaps you don't need to do anything other than show the Facebook login button.
2) Option 2
You assume the person is a user of your app, and do whatever you need to do to show the UI. But you won't be running your full normal logic - this will be application specific to you .
3) Option 3
Manually set the cookie value fblo_<APPID> to n (instead of 'y'). Remember this cookie is set on your domain so you're allowed to change it. *Depending upon your development environment this will vary, but it needs to be done client side, and you may need to specify path of `/' and your cookie domain).
Run the getLoginStatus(..., true) - it will not be blocked now because the cookie is now n. However you must not run your normal logic here - because all you want to do is check if the user is actually a Facebook user and/or still authenticated with your app.
Manually set the cookie value back to y
Unfortunately I can't recommend this solution due to weird race conditions. It almost almost works, but FB could deliberately or accidentally break it at any time - and it actually ends up still getting confused thinking you're really logged in when you aren't. Plus it could have all kinds of complications with other plugins I haven't even observed.
I wish the getLoginStatus would just always run and give accurate information, but this is the only true solution I see. And it's been this way for 8 years so I think we're stuck with it.
4) Option 4 - Set your own cookie
You always have the option to set your own cookies to indicate certain things, like 'this user has at some point logged into Facebook' or 'this user is authenticated with my app'. But I'm cautious about doing this because it can quickly get complicated.
Incidentally I revisited this issue because I'm using the Messenger plugin for my website and I don't want it to display at all unless I know the person has a Facebook account. So I need an accurate response to login status.
This was happening to me until I turn on my browser to allow third-party websites to save and read cookies.
To do this go to
settings > advanced > site settings > Cookies and site data
Then uncheck the option blocking third-party websites from saving and reading cookies.
This might not be a good option but it solves these issues for me.
You just need make your site URL from http to https
DO NOT use http
I had the same issue in IE. Flimzy's answer got me thinking. I tried running IE as administrator and it worked.
I had the same problem, I fixed this by clearing all cache and cookies.
You have to test it from the live domain (which you provided in the app).
I had the same problem when testing locally (using local domain).
In my case I was using Brave browser which didn't allow cookies due to which it was giving status unknown. I switched to chrome and now it is working.
I am trying to tweak the Parse Express tutorial:
https://www.anyimg.org/ and https://github.com/ParsePlatform/Anyimg
Basically, instead of starting with their default home page, I always show a login page if the user has not been logged in. I was able to do that by adding a simple check for Parse.User.Current() at the Homepage endpoint and redirecting to login if they are not looged in.
For my next step, I want to allow Facebook login. So I tweaked the login.ejs as follows:
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
Parse.FacebookUtils.init({
appId : '254642391362596',
status : true,
xfbml : true
});
};
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
function fLogin() {
/*Parse.FacebookUtils.logIn(null, {
*//*success: function(user) {
alert("login success with user " + JSON.stringify(user));
if (!user.existed()) {
alert("User signed up and logged in through Facebook!");
} else {
alert("User logged in through Facebook!");
}
//FB.api('/me', function(response) {
// alert("got fb me api=" + JSON.stringify(response));
//});
},
error: function(user, error) {
alert("User cancelled the Facebook login or did not fully authorize.");
}*//*
});*/
// log in with Parse
Parse.FacebookUtils.logIn(authData, {
success: this._fbLoginSuccess,
error: this._fbLoginError
});
}
</script>
<button class="btn-facebook btn-large" onclick="fLogin();"><img src="./images/FB-f-Logo__blue_58.png"> <span class="btn-facebook-text">Login with Facebook</span></button>
The good news: When I try the commented block without the login block, I get a FaceBook login prompt, and I can go to the DataBrowser and see AuthData there.
However, if I use the //Login block, nothing seems to happen.
Also, if FB login is a success what do I change in app.js or user.js to allow the home page to render? I have been searching docs and SO for a day now, and I don't see any clear docs on this.
Thanks for your help!
Note: I am rather new to both Parse and Express, but I have been able to make progress mostly on my own (please see my other postings here).
I have made progress. The code above essentially works. Remove unwanted alerts from above and use window.location.href = '"home"/one-of-my-routes". However, I am still unable to send a post to my users.js page. Any help will be appreciated
What you are trying to do is definitely possible (I've done it), but can't be achieved with the method you are using right now. Basically you can't access the Parse.User.current() in Express on the server if you do a login with Facebook JS SDK on the browser. It doesn't work. (See this question in Parse forums.)
The only way you can achieve what you want, as far as I know, is using the undocumented parseFacebookUserSession middleware.
Edit: Add step-by-step detailed instructions
To log in the user with Facebook on Express (server) you simply need to follow the steps detailed on the middleware's github repo. Start by adding the file parse-facebook-user-session.js into the cloud folder. Then add the code shown on the readme to app.js, like this:
var parseExpressHttpsRedirect = require('parse-express-https-redirect');
var parseExpressCookieSession = require('parse-express-cookie-session');
var parseFacebookUserSession = require('cloud/parse-facebook-user-session');
app.use(parseExpressHttpsRedirect()); // Require user to be on HTTPS.
app.use(express.bodyParser()); // Middleware for reading request body
app.use(express.cookieParser('123456789')); // YOUR_SIGNING_SECRET
app.use(parseExpressCookieSession({ cookie: { maxAge: 3600000 } }));
var fbLogin = parseFacebookUserSession({
clientId: 'FB_APP_ID',
appSecret: 'FB_APP_SECRET',
verbose: true,
redirectUri: '/profile' // where the user will be redirected to after getting a token from Facebook
});
// This route will require FB login. If the user is not logged in, it will be redirected to FB
app.get('/events/new', fbLogin, events.new);
// A route to log out
app.get('/logout', function(req, res) {
Parse.User.logOut();
res.redirect('/');
});
Some notes:
You must use HTTPS
You must enable the 'Add Field' Class Level Permission for the _User class using the Data Browser
You must enable 'Allow client class creation' in the app Settings (see the readme)
A new class ParseFacebookTokenRequest will be created on the Data Browser. Disable all it's Class Level Permissions (again, see the readme)
Important: According to a Parse Engineer, it's possible to log in the user client side using the FB JS SDK. I haven't done this but it's somewhat explained in this issue.
I recently found this useful post. Albert, this has the become() that you suggested. And this helped me at least get one version working.
Parse Javascript SDK -- Save client-side `user` as server-side ` Parse.User.current()`
Friends,
I have set up a facebook login for my website using JS SDK.
If the use is logged in through JS SDK, should we cross verify whether the session is valid in the server side also as client side can easily be fabricated.
Since I use JS SDK, server will not have access to the facebook session.
If I need to verify the session at the server end, can i use php-sdk adn extern the session like it is specified in https://developers.facebook.com/docs/reference/php/ ? In this case I need to enable CURL PHP extension to get this running and worried if performance will go down when using php sdk.
Could you please help me in finding answers for the above queries?
The php sdk and the javascript are the completely opposite, of what Julian H. Lam said, in fact they were build to be used together.
On the php sdk documentation you can find this:
Integration with the Facebook SDK for JavaScript
Used in conjunction with the Facebook SDK for JavaScript, the PHP SDK
can share user sessions seamlessly across the client and server. If a
user is logged in with Facebook and has authorized your app, the
JavaScript SDK can pick up the user session persist this in a cookie
which, which the PHP SDK reads without any intervention on the
developer's part.
To enable this functionality, ensure that when you embed and
initialise the JS SDK, you set both the status and the cookie
parameters of the object passed to FB.init() to true.
And by using basic logic this makes all sense, on the client side you can create listeners to retrieve user status(if he's logged in, if he has granted permissions, if he has logout), doing this kind of actions on the server side doesn't make any sense at all.
So my advice for you is to use Javascript SDK to handle user events, like the ones I mentioned before, and to handle the responses from the actions of the users, like when the user does a like, or shares a post using the feed dialogue, etc.
With the php SDK you just check if you have a valid user, since you're sharing the same cookie for the client side and for the server side after you handle the login proccess with the javascript SDK, if you do this $fb_id = $facebook->getUser() (after initializing the PHP SDK of course), you'll get the user facebook id, now that you know you have a valid user, you can use the PHP SDK to query information about the user, post on user behalf, etc.
Here's an example of a proper loading of the javascript SDK with cookie support:
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : 'YOUR_APP_ID', // App ID from the app dashboard
channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel file for x-domain comms
status : true, // Check Facebook Login status
xfbml : true, // Look for social plugins on the page
cookie : true
});
// Additional initialization code such as adding Event Listeners goes here
};
// Load the SDK asynchronously
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
And this is a simple code on the server side just to enlighten you:
require_once("facebook.php");
$config = array();
$config[‘appId’] = 'YOUR_APP_ID';
$config[‘secret’] = 'YOUR_APP_SECRET';
$config[‘fileUpload’] = false; // optional
$facebook = new Facebook($config);
try {
$user_profile = $facebook->api('/me','GET');
$user_name = $user_profile['name'];
$user_email = $user_profile['email'];
} catch(FacebookApiException $e) {
// If the user is logged out, you can have a
// user ID even though the access token is invalid.
// In this case, we'll get an exception, so we'll
// just ask the user to login again here.
}
PS: this server side code, only works if the user has already granted permissions with the scope email
There are two parts to this question: Firstly, there is a difference in the UI flow. See: https://developers.facebook.com/docs/concepts/login/login-architecture/
1) Browser side with JS SDK. You start off with oauth 2.0 dialog, obtaining the Access Token and then using this to access the Facebook API.
2) Server side uses signed_request posted to the server. With this, you can extract the user_id. See: https://developers.facebook.com/docs/howtos/login/signed-request/ -
Step 1 - describe the signed_request, how you can obtain it from PHP or JS SDK
Step 2 - how to verify that the signed_request is not fabricated.
Oauth token from other providers can be integrated with FB. See my Dropbox example: apps.facebook.com/fileglu/ - circa Sept 2011, also check out the technical section for implementation details, including CSRF, CORS and avoiding javascript cryptography.
The Facebook javascript library and the php SDK can essentially be considered two entities that do not talk to one another, as one is client-side, and the other is server-side.
The php SDK gives you greater fine-grained control over a user's login session, while the javascript library is easier to get started.
Typically, a user logged in via the javascript library is not automatically logged in on the server side, although in some cases, it may be possible to send the access token from client to server side. It is not advised, however, as this data can be intercepted.
This related question talks about sending the access token (as retrieved from the JS library) to the server side.
In essence:
FB.login(function(response) {
var access_token = response.authResponse.accessToken;
// Make an ajax call here to your server-side, and send access_token in.
});
I am trying to use Facebook API for likes on my web page. Currently trying to use all.js, it fails to load the file at url below as it translates it to file://connect.
//connect.facebook.net/en_US/all.js#xfbml=1
Changing url explicitly to http: gives a different error.
Do we need APPID for initializing this API and use all.js or can it be used without APPID?
Reference URL:
http://developers.facebook.com/docs/reference/plugins/like/
According to this answer, an AppId is required. The tool in the reference URL you listed will insert your AppId in the code it generates.
(function(d, s, id) {
...
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=xxxxxxxx";
...
}(document, 'script', 'facebook-jssdk'));
You are probably getting the file://connect error because you are testing by opening a local file in your web browser instead of a file served by a real web server. When you don't specify the protocol in a link, the browser will assume it's the same protocol as the current page.
From the Facebook documentation:
Note: The URLs in the code are protocol relative. This lets the
browser load the SDK over the same protocol (HTTP or HTTPS) as the
containing page, which will prevent "Insecure Content" warnings.
Missing http and https in the code is intentional.
I'm using FB.ui() like so:
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '##########', // App ID
channelUrl : '//www.xxxxxxxxxx.com/channel.php', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional initialization code here
};
// 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";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
Then, here's the link to send the message:
<a href='#' onClick="
FB.ui({
method: 'send',
name: 'Bla bla bla',
link: 'http://www.xxxxxxxxxxx.com',
to: ###########,
//redirect_uri: 'http://www.xxxxxxxxxxx.com/fb/'
});
">Send a message</a>
PROBLEM:
This works like a charm for me and every computer/browser I've tested on. But my client gets the following error message very frequently:
API Error Code: 191
API Error Description: The specified URL is not owned by the application
Error Message: redirect_uri is not owned by the application
This has me totally stumped! Is anything wrong with my code? And if so, why can't I EVER reproduce this bug while my client consistently can on multiple computers/browsers?
PS: If you want to try yourself, the page is live here. You'll have to authorize the app, but I promise nothing creepy will happen.
EDIT: The error mentions the redirect_uri, which you'll notice is commented out in my code. The reason is because when I include that parameter, the dialogue doesn't close when I hit "close".
EDIT2: I was able to reproduce this bug on a friend's computer, and CBroe also confirmed it. So, (setting aside the mystery of why I still can't produce it myself), the thing that has me most stumped is why does this only happen half of the time?? If my code is incorrect it should never work, right??
Here's the url from the error message:
https://www.facebook.com/dialog/send?display=popup&link=http%3A%2F%2Fwww.streetofwalls.com&locale=en_US&name=Career%20Networking%20powered%20by%20Street%20of%20Walls&next=http%3A%2F%2Fstatic.ak.facebook.com%2Fconnect%2Fxd_arbiter.php%3Fversion%3D8%23cb%3Df2c657ef78%26origin%3Dhttp%253A%252F%252Fwww.streetofwalls.com%252Ff3575a615c%26domain%3Dwww.streetofwalls.com%26relation%3Dopener%26frame%3Df1ca46b43c%26result%3D%2522xxRESULTTOKENxx%2522&sdk=joey&show_error=true&to=573501273
After url_decode() version:
https://www.facebook.com/dialog/send?display=popup&link=http://www.streetofwalls.com&locale=en_US&name=Career Networking powered by Street of Walls&next=http://static.ak.facebook.com/connect/xd_arbiter.php?version=8#cb=f2c657ef78&origin=http%3A%2F%2Fwww.streetofwalls.com%2Ff3575a615c&domain=www.streetofwalls.com&relation=opener&frame=f1ca46b43c&result=%22xxRESULTTOKENxx%22&sdk=joey&show_error=true&to=573501273
EDIT3:
Part of this puzzle is solved. The times when the error occurs are the result of FB.init() not working. I've wrapped the FB.ui() in FB.getLoginStatus(function(response){ \\... } so now you can see a more useful error in the console. The open question is... WHY DOES FB.init() fail so often?
This is due to a configuration error between your redirect_uri and the settings that you have specified for your Facebook app. See the answer to this question.
The redirect_uri should be equal (or relative) to the Site URL that you set in your Facebook app's settings. So make sure your Site URL is set and that it points to a directory that is equal to or lower than your redirect_uri. Also, make sure you have set the app's domain correct in Facebook's settings.
For example:
App domain: streetofwalls.com
Site URL: / Secure Canvas URL: / Secure Page Tab URL: http://www.streetofwalls.com
First you load the following script in the head of your page:
<script type="text/javascript" src="http://www.streetofwalls.com/wp-content/themes/streetofwalls/js/main.js"></script>
Inside that script you try to load the FB JavaScript SDK asynchronously. The SDK requires the fb-root element in order to load properly as stated in the docs. But your fb-root element might not be rendered yet, so here is the problem I guess.
Put the window.fbAsyncInit = ... and the code for loading the SDK asynchronously inside jQuery(document).ready(function($) { ... }); and you should be fine.
For debugging you could also try to load the Facebook SDK synchronously.
Another thing I have noticed:
You have two script tags inside the head of your site which load the FB JavaScript SDK. You should remove both.
So Nitzan deserves the credit for this for his insightful comment, but here's the solution.
The error message I was getting was a result of the fact that FB.init() wasn't loading, or at least it wasn't loading in the proper order with respect to the rest of the page. I copied the code from the Facebook Developer docs and it loads asynchronously... which turns out to be kind of a big pain in the ass...
So instead of what I had, I switched to loading it the old fashioned way:
FB.init({
appId : '##########', // App ID
channelUrl : '//www.xxxxxxxxxx.com/channel.php', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
This, combined with some reordering of the other scripts, seems to have resolved my problem.