I'm trying to make facebook messenger checkbox work, I've added the following code to my html
window.fbAsyncInit = function() {
FB.init({
appId: "{{ fb_app_id }}",
xfbml: true,
version: "v2.6"
});
FB.Event.subscribe('messenger_checkbox', function(e) {
console.log("messenger_checkbox event");
console.log(e);
if (e.event == 'rendered') {
console.log("Plugin was rendered");
} else if (e.event == 'checkbox') {
var checkboxState = e.state;
console.log("Checkbox state: " + checkboxState);
} else if (e.event == 'not_you') {
console.log("User clicked 'not you'");
} else if (e.event == 'hidden') {
console.log("Plugin was hidden");
}
});
};
(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'));
<div class="fb-messenger-checkbox"
origin="my.site.com"
page_id="{{ fb_page_id }}"
messenger_app_id="{{ fb_app_id }}"
user_ref="{{ user_token }}"
prechecked="true"
allow_login="true"
size="xlarge"></div>
But whenever I refresh the page, the messenger checkbox doesn't show up, instead I get an error in chrome's console
Refused to display 'https://www.facebook.com/v2.6/plugins/messenger_checkbox.php?allow_login=tr…&user_ref=1tYPmZaYMKXKfcZiUtaENYTXH3H49OTP7tJrt5fyobCgepqziMA0Z037T5gto9o3'
in a frame because an ancestor violates the following Content Security Policy directive:
"frame-ancestors https://www.facebook.com".
Anyone might know how to fix this? Been stuck for the last 24hrs.
Edit: Docs states that i should add my domain as whitelist, i already did, but this error still persists.
There are two solutions to this problem:
Install the chrome Disable Content-Security-Policy
plugin
and use it to disable content security policy headers when viewing
the page where your checkbox plugin is used
Whitelist the domain (including the protocol and port) of the page where the plugin is hosted. When testing this locally, I was hosting the plugin on a nodejs app which was running on http://localhost:3000/signup. I was also using ngrok to allow me to expose my local server remotely so that I can handle the opt-in callback on my local machine. It turns out that you must whitelist the domain that you entered into your browser URL field to access the page. This might seem obvious, but I kept trying to use the ngrok domain, which looked like http://abc364ef.ngrok.io and didn't work. In my case, since I was accessing the page through http://localhost:3000/signup, I had to use the following whitelist command:
curl -X POST -H "Content-Type: application/json" -d '{
"whitelisted_domains":[
"http://localhost:3000"
]
}' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"
I also had to use this same domain in the origin attribute of the <div class="fb-messenger-checkbox" block. I discovered afterwards that I could've actually used the ngrok domain, however, I would've had to access the page using http://abc364ef.ngrok.io/signup, which was too slow, so I preferred to stick with http://localhost:3000.
You should whitelist your domain https://developers.facebook.com/docs/messenger-platform/messenger-profile/domain-whitelisting
1) Click Settings at the top of your Page
2) Click Messenger Platform on the left
3) Edit whitelisted domains for your page in the Whitelisted Domains section
In our project we have identified several failure points, here are the troubleshooting tips:
user_ref has to be always unique. (Even for every page refresh!)
Check if the domain you're displaying the checkbox in has been
whitelisted. In case you call your form from a similar domain
https://your-domain.com/facebook/facebook.aspx then whitelist
https://your-domain.com/facebook too!
If the allow_login parameter is set to false, you will need to have a valid Facebook user session (i.e. not logged in as a page) otherwise the plugin will be hidden.
Is the origin attribute the same as the domain where you host the
plugin?
Testing on localhost is not supported by Facebook right now. (At least Facebook says so. But you can overcome this by using ngrok.)
Check that appId in Facebook Javascript SDK and messenger_app_id in <div class="fb-messenger-checkbox"have the same values.
Related
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.
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()`
I'm running an error very similar with this one: Facebook Login API HTTPS Issue.
I have a website use facebook authentication, the Facebook login is no problem. But the Facebook like-button get troubled when been clicked (test fail on Chrome, Safari, Firefox, in OSX), the error message is:
Blocked a frame with origin "https://www.facebook.com" from accessing a
frame with origin "http://static.ak.facebook.com". The frame requesting
access has a protocol of "https", the frame being accessed has a protocol
of "http". Protocols must match.
I've searched all over and find no solutions.
It seems like that when the like-button is clicked, it pop out a frame from https://facebook.com callback and trying to request http://static.ak.facebook.com thus cause protocol mismatch?!
Here's what I put right after <body> tag
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : 'appid', // App ID from the app dashboard
channelUrl : '//mydomain/channel.html', // Channel file for x-domain comms
status : true, // Check Facebook Login status
xfbml : true // Look for social plugins on the page
});
// 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/zh_TW/all.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
and the channel file at http://mydomain/channel
<script src="//connect.facebook.net/zh_TW/all.js"></script>
and here's how I use the like-button
<div class="fb-like" data-href=url data-send="true" data-width="450"
data-show-faces="true"></div>
Really needs help, please!
In your first script tag you can tell Facebook explicitly to use HTTPS...
Add the line:
FB._https = (window.location.protocol == "https:");
Add it before the FB.init function call, just below or in place of the comment:
// init the FB JS SDK
This will ensure that Facebook's servers load any required libraries their end over https.
Hope this helps.
Reviewing the js code on Facebook there are multiple urls containing hard coded strings for
http://static .../rsrc.php
it's possible those are the files triggering the error.
This may be something Facebook needs to update.
On a side note, it may be possible to download that js file from Facebook and store it on your server and remove the hard coded http string. I would test this further but I am on my phone at the moment.
I'm trying to follow the tutorial here. But when I call FB.init(...) with what appears to be valid and correct parameters I get the error message: "Given URL is not allowed by the Application configuration.: One or more of the given URLs is not allowed by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains." I have searched (1 2) for this error, but everyone else seems to be having trouble simply setting the Site URL for their Facebook Application configuration. I'm 99% certain I have set this correctly - but obviously I'm doing something wrong.
Here is my code that is causing problems. I have replaced some of the info with "XXX" and "YYY" for privacy reasons.
<html>
<body>
<h1>Facebook</h1>
<div id="fb-root"></div>
<script>
// Additional JS functions here
window.fbAsyncInit = function() {
FB.init({
appId : 'XXX', // App ID
channelUrl : '//YYY.com/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
});
};//window.fbAsyncInit()
// 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 = "http://connect.facebook.net/en_US/all/debug.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
</body>
</html>
Notice that I had to change the js.src parameter near the bottom of the code from the example given in the tutorial. I doubt this is causing my specific problem, but casts some concern on the quality of the code in the tutorial. (I hate it when tutorial code doesn't work - what's the point?)
You can see in the code above I have replaced the root of my domain name to "YYY". Keeping with this simple replacement here are some of the values from my Facebook Application configuration:
App ID: "XXX"
Display Name: "[blah blah blah]"
Namespace: "YYY"
App Domains: "YYY.com"
Sandbox Mode: "Enabled"
Canvas Page: "http://apps.facebook.com/YYY"
Canvas URL: "http://YYY.com/canvas/"
I'm not sure what other detail you may need to help me with this. All of the URL's listed are functional. Thanks for any help!
Notice that I had to change the js.src parameter near the bottom of the code from the example given in the tutorial.
Why? Are you testing by just calling your page in the browser from the file system, and not over HTTP via a local web server?
If the latter is the case, then you have no “domain” that Facebook could verify your request origin against. Set up a local web server, call your document via it, and try again,
I'm starting out my little quest into the world of the Meteor framework and I thought it'd be fun to do something a little bit facebooky with it.
step one was to follow the create an app tutorial in meteor then add the FB code to the template as found here: https://developers.facebook.com/docs/opengraph/tutorial/#authenticate
Sadly it doesn't seem to work on the page at all. In fact, I've just realized that if I add something like alert('foo'); to my meteor page it doesn't execute. Interesting.
So Metor, despite being completely amazing doesn't work like I expect it to... (shock, horror!).
How do I execute client side JS in this framework? (specifcially with the hope of creating a facebook JS object on the page?)
Thanks!
UPDATE (Jan 2013): Meteor released 0.5.0 which has built in authentication and facebook login support.
Documentation is here: http://docs.meteor.com/#accountsui
Essentially you run some commands in the shell
meteor add accounts-password
meteor add accounts-ui
meteor add accounts-facebook
then in your code you add the login button.
{{loginButtons}}
then you're in.
It's probably a very bad idea to do any sort of authentication to an external API, while passing around App IDs, secrets, etc, from the browser (client in the meteor stack).
I've implemented full facebook authentication on the server successfully.
Add the accounts-facebook smart package by running meteor add accounts-facebook from your application's working directory. This will allow you to be able to configure support for both the OAuth single user as well as the OAuth multi-user facebook authentication workflows. Please see Meteor Accounts System docs for more info.
After adding the accounts-facebook smart package, you may do something along these lines...
Under your application's working directory, in server/server.js (or similar file under the server directory), implement something like this:
Meteor.startup(function () {
Accounts.loginServiceConfiguration.remove({
service: "facebook"
});
Accounts.loginServiceConfiguration.insert({
service: "facebook",
appId: process.env.FACEBOOK_APP_ID,
secret: process.env.FACEBOOK_APP_SECRET
});
});
Take note of these lines:
appId: process.env.FACEBOOK_APP_ID,
secret: process.env.FACEBOOK_APP_SECRET
You will need to set the environment variables FACEBOOK_APP_ID and FACEBOOK_APP_SECRET properly for the above code to use the correct values.
In client/client.js (or similar file under the client directory), implement something like this:
Meteor.startup(function() {
Meteor.loginWithFacebook({
requestPermissions: ['publish_actions']
}, function (err) {
if (err) {
Session.set('errorMessage', err.reason || 'Unknown error');
}
});
});
As per Meteor.loginWithExternalService([options], [callback]), the callback function for Meteor.loginWithFacebook allows you to easily distinguish between error states, and non-error states:
Optional callback. Called with no arguments on success, or with a
single Error argument on failure.
It appears that running client side code is done by placing it inside the "myapp.js" file
Template.hello.greeting = function () {
// ADD YOUR CODE HERE
alert('foo');
return "Welcome to matchmakeur.";
};
So in order to connect your code to Facebook authentication you've got to do something like
Template.fbconnect.connect = function () {
window.fbAsyncInit = function() {
FB.init({
appId : '[YOUR_APP_ID]', // App ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
};
// Load the SDK Asynchronously
(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));
return true;
};
and have a template
<template name="fbconnect">
<div id="fb-root"></div>
{{connect}}
<fb:login-button show-faces="true" width="200" max-rows="1" scope="publish_actions">
</fb:login-button>
<template>
It is not a bad idea to use Facebook JavaScript SDK if you want to build a full client-side app with Meteor...
Alex C answer works at first glance, but I had some problems with FB.logout() after "navigating" and going back to the "page" where <div id="fb-root"></div> was defined, because when fb-root is re-rendered, FB.logout() stops working.
So I think the best way to load Facebook JavaScript SDK is to use a Template created callback:
Template.fbLogin.created = function () {
if (!Session.get("is Facebook JDK loaded?")) {
Session.set("is Facebook JDK loaded?", true);
// https://developers.facebook.com/docs/reference/javascript/
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : '[YOUR_APP_ID]', // App ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional initialization code such as adding Event Listeners goes here
};
// Load the SDK's source Asynchronously
// Note that the debug version is being actively developed and might
// contain some type checks that are overly strict.
// Please report such bugs using the bugs tool.
(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));
}
};
Also, other thing that needs to be done for FB.logout() to work correctly is using a constant template helper around <div id="fb-root"></div>. So your code should be like this:
<body>
{{#constant}}
<div id="fb-root"></div>
{{/constant}}
<!-- rest of body... -->
I also found that it is necessary to put fb-root immediately after body.
There is a live app running code like this at http://evee.meteor.com
And you can find its source-code here: https://github.com/fjsj/evee/
(check fbLogin.js for created and app.html for constant and fb-root)
Bonus (how to serve a channel.html file with Meteor)
As of January 2013, Meteor does not support server-side routes to serve static HTML. So how to make a channel.html with Meteor? Putting it in /public won't work, since .html files are processed by Meteor as templates.
By using Meteor internals, it is possible! As suggested by this answer, we need to use a middleware-like approach (powered by Connect). Just put this on your /server (note it will be served at yourapp.meteor.com/fb/channel.html):
// serve channel.html file
var connect = __meteor_bootstrap__.require("connect");
__meteor_bootstrap__.app
.use(connect.query())
.use(function(req, res, next) {
// Need to create a Fiber since we're using synchronous http
// calls and nothing else is wrapping this in a fiber
// automatically
Fiber(function () {
if (req.url === "/fb/channel.html") {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('<script src="//connect.facebook.net/en_US/all.js"></script>');
} else {
// not an channel.html request. pass to next middleware.
next();
return;
}
}).run();
});
Also this is working in production and the code is available at GitHub (includes cache headers).
You could also implement a Template event on any selector and then implement your FB javascript code. For example, recreating the Facebook Share button which has been disabled can be done by using one of the old deprecated FB share images, binding the selector to a Template event, and then using the FB.ui dialogs to post to the users Wall and share content from your site. I tested it today and it works. I imagine you could do something similar with the login if you really wanted to customize the experience some.