Getting facebook authentication running within the MeteorJS framework? - facebook

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.

Related

Parse.com Express complete login process with Facebook

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 have followed the steps in 'Getting Started with Facebook Login for Web' but adding the Facebook SDK for Javascript does not seem to work

I tried following the steps outlined in 'Getting Started with Facebook Login for Web' however they do not seem to be working.
I have followed the steps on this page; I retrieved my App ID (Step 1), I added the Facebook SDK for Javascript (Step 2) (Minus the channel URL, which I read elsewhere in the documentation is optional, as I am working on this page offline rather than hosted on a server), I then added the login code (Step 3).
I'm not sure why it isn't working. I am getting the error 'Failed to load resource' in the console log.
Full Code:
<html>
<head></head>
<body>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '1233456789', // App ID
//channelUrl : '//WWW.YOUR_DOMAIN.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
});
// Here we subscribe to the auth.authResponseChange JavaScript event. This event is fired
// for any auth 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 user interaction (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";
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.-->
<fb:login-button show-faces="true" width="200" max-rows="1"></fb:login-button>
</body>
</html>
If you look closely, the Facebook SDK download line starts with //, not http:// or https://. That means that the script will be downloaded with using the same protocol of the embedding page. You are opening a local file, which shows up as file:// in the navigation bar, so the browser tries to download the SDK via file:// and fails.
Long story made short: add a https: before the two //, like this:
js.src = "https://connect.facebook.net/en_US/all.js"
Longer solution (but cleaner): use a local development server. If you have PHP 5.4 installed on your PC, open a command line, navigate to the project folder and then launch:
php -S localhost:8080
The open your browser and enter localhost:8080 in the address bar.

FB.init(...) error: "Given URL is not allowed by the Application configuration."

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,

FB.ui puzzle: inconsistent error code 191... (seems like FB.init is frequently not working)

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.

Facebook "like" button

My facebook like button loads really slow, so as a solution I read this;
http://developers.facebook.com/docs/reference/javascript/
The only part I am confused about are these two lines;
appId : 'YOUR_APP_ID', // App ID
channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
I am unsure what would go in the above.
Could someone enlighten me? Thank you .
Edit: This is how my code looks like (for facebook like button), and I know it isn't right..
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : 'YOUR_APP_ID', // App ID
channelUrl : '//WWW.YOUR_DOMAIN.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
});
// Additional initialization code here
};
// 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));
</script>
<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_GB/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
I'm not quite sure you need this.
For your like button you should be using https://developers.facebook.com/docs/reference/plugins/like/.
The FB JavaScript SDK is used when you're writing applications that would relay on data they receive from the Facebook API. In your case you're only using a "Like button". That doesn't depend on any data thus you don't need it.
Channel File
The channel file addresses some issues with cross domain communication in certain browsers. The contents of the channel.html file can be just a single line:
<script src="//connect.facebook.net/en_US/all.js"></script>
It is important for the channel file to be cached for as long as possible. When serving this file, you must send valid Expires headers with a long expiration period. This will ensure the channel file is cached by the browser which is important for a smooth user experience. Without proper caching, cross domain communication will become very slow and users will suffer a severely degraded experience. A simple way to do this in PHP is:
<?php
$cache_expire = 60*60*24*365;
header("Pragma: public");
header("Cache-Control: max-age=".$cache_expire);
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$cache_expire) . ' GMT');
?>
<script src="//connect.facebook.net/en_US/all.js"></script>
The channelUrl parameter is optional, but recommended. Providing a channel file can help address three specific known issues. First, pages that include code to communicate across frames may cause Social Plugins to show up as blank without a channelUrl. Second, if no channelUrl is provided and a page includes auto-playing audio or video, the user may hear two streams of audio because the page has been loaded a second time in the background for cross domain communication. Third, a channel file will prevent inclusion of extra hits in your server-side logs. If you do not specify a channelUrl, you can remove page views containing fb_xd_bust or fb_xd_fragment parameters from your logs to ensure proper counts.
The channelUrl must be a fully qualified URL matching the page on which you include the SDK. In other words, the channel file domain must include www if your site is served using www, and if you modify document.domain on your page you must make the same document.domain change in the channel.html file as well. The protocols must also match. If your page is served over https, your channelUrl must also be https. Remember to use the matching protocol for the script src as well. The sample code above uses protocol-relative URLs which should handle most https cases properly.
App Id
This is your Facebook application ID. Go to https://developers.facebook.com/apps and select the application you setup. If you didn't setup an application, then read: http://developers.facebook.com/docs/guides/canvas/
The page you linked to is for the Javascript SDK, which is probably not what you want, unless you want to do more than just plop a "Like" button on your page. To use the SDK, you have to have a Facebook app and add some code to your website, which is where you'll get the App ID.
The "Like" button documentation is here, and there's not a whole lot you can do to get it to load faster if it's Facebook taking a while to load the page, unless you want to add a full-fledged app and maybe use that to "Like" pages for the user, but I'm not sure if that's even possible. Pull up Firebug or Chrome Dev Tools and see what's taking the longest, but it's probably just on Facebook's end.