You can integrate Facebook Chat into your Web-based, desktop, or mobile instant messaging products. Your instant messaging client connects to Facebook Chat via the Jabber/XMPP service. This document describes the features and limitations of Facebook Chat's XMPP protocol for the developer who intends to implement a Facebook Chat client.
Before reading this document, you should be familiar with the terms and concepts involved in XMPP chat clients and servers.
Please do not use this API to send spammy messages to users. Facebook takes user experience and spam extremely seriously and if users report your app as using the Chat API to spam them, we will disable your app.
Facebook Chat currently supports the following features:
Facebook Chat should be compatible with every XMPP client, but is not a full XMPP server. It should be thought of as a proxy into the world of Facebook Chat on www.facebook.com. As a result, it has several behaviors that differ slightly from what you would expect from a traditional XMPP service:
jabber:iq:auth
namespace as described in XEP-0078 is not currently supported.You can authenticate your chat client users with one of two authentication mechanisms: X-FACEBOOK-PLATFORM (Facebook Platform) and DIGEST-MD5 (username/password). Facebook recommends you use the X-FACEBOOK-PLATFORM mechanism to connect to Facebook Chat whenever possible, because it provides a better user experience using simple Facebook Platform authentication.
We support a custom SASL mechanism called X-FACEBOOK-PLATFORM that allows clients to connect to chat using Facebook authentication. This mechanism is preferred for any application that is oriented toward social media in general or Facebook in particular, especially applications that are already integrated with Facebook Platform.
In order to connect using this mechanism, the user must first log in to your application and grant the xmpp_login
extended permission. Follow the client side flow to get a valid access_token for the user with the xmpp_login
extended permission.
Your application may now log in to Facebook Chat via Jabber using the X-FACEBOOK-PLATFORM mechanism. The user's Jabber ID will be assigned during the resource binding step of XMPP. Please keep in mind that while all of the messages defined by the X-FACEBOOK-PLATFORM mechanism are UTF-8 strings, XMPP specifies that they should be Base64-encoded before being sent over the wire.
The mechanism starts with a server challenge, in the form of a common HTTP query string: an ampersand-separated sequence of equals-sign-delimited key/value pairs. The keys and values are UTF-8-encoded and URL-encoded. The query string contains two items: method
and nonce
.
The client's reply should be a similarly-encoded query string prepared as if it were going to call a method against the Facebook API. The call should contain the following parameters:
string method
: Should be the same as the method specified by the server.string api_key
: The application key associated with the calling application.string access_token
: The access_token obtained in the above step.float call_id
: The request's sequence number.string v
: This must be set to 1.0 to use this version of the API.string format
: Optional - Ignored.string cnonce
: Optional - Client-selected nonce. Ignored.string nonce
: Should be the same as the nonce specified by the server.The server will then respond with a success or failure message. Note that this needs to be over TLS or you'll get an error.
The DIGEST-MD5 SASL mechanism is available to support traditional XMPP or multi-protocol IM clients that are not customized for (or even aware of) Facebook. This mechanism requires prompting the user for his or her password; therefore, it should only be used when necessary. In particular, it MUST NOT be used for any client that:
If your application does any of the above, you must use Facebook Platform authentication instead.
The user's Jabber ID is simply his or her Facebook user name with @chat.facebook.com
appended. A user must have a Facebook username to use DIGEST-MD5. After the user gets his or her username, he or she must log out of and into Facebook once for us to store the special hash of the password.
Clients should retrieve their user's vCard from the server according to XEP-0054 in order to be able to display a more natural name to the user. For example:
<iq id='1' type='get'><vCard xmlns='vcard-temp'/></iq>
In order to provide the best user experience, we recommend your chat integration do the following:
conflict
.group
elements.chat.facebook.com
or facebook.com
should be displayed as administrative messages.Below is some sample, self-explanatory code that shows you how to authenticate a user and connect with XMPP.
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
$STREAM_XML = '<stream:stream '.
'xmlns:stream="http://etherx.jabber.org/streams" '.
'version="1.0" xmlns="jabber:client" to="chat.facebook.com" '.
'xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">';
$AUTH_XML = '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" '.
'mechanism="X-FACEBOOK-PLATFORM"></auth>';
$CLOSE_XML = '</stream:stream>';
$RESOURCE_XML = '<iq type="set" id="3">'.
'<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">'.
'<resource>fb_xmpp_script</resource></bind></iq>';
$SESSION_XML = '<iq type="set" id="4" to="chat.facebook.com">'.
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>';
$START_TLS = '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>';
function open_connection($server) {
print "[INFO] Opening connection... ";
$fp = fsockopen($server, 5222, $errno, $errstr);
if (!$fp) {
print "$errstr ($errno)<br>";
} else {
print "connnection open<br>";
}
return $fp;
}
function send_xml($fp, $xml) {
fwrite($fp, $xml);
}
function recv_xml($fp, $size=4096) {
$xml = fread($fp, $size);
if ($xml === "") {
return null;
}
// parses xml
$xml_parser = xml_parser_create();
xml_parse_into_struct($xml_parser, $xml, $val, $index);
xml_parser_free($xml_parser);
return array($val, $index);
}
function find_xmpp($fp, $tag, $value=null, &$ret=null) {
static $val = null, $index = null;
do {
if ($val === null && $index === null) {
list($val, $index) = recv_xml($fp);
if ($val === null || $index === null) {
return false;
}
}
foreach ($index as $tag_key => $tag_array) {
if ($tag_key === $tag) {
if ($value === null) {
if (isset($val[$tag_array[0]]['value'])) {
$ret = $val[$tag_array[0]]['value'];
}
return true;
}
foreach ($tag_array as $i => $pos) {
if ($val[$pos]['tag'] === $tag && isset($val[$pos]['value']) &&
$val[$pos]['value'] === $value) {
$ret = $val[$pos]['value'];
return true;
}
}
}
}
$val = $index = null;
} while (!feof($fp));
return false;
}
function xmpp_connect($options, $access_token) {
global $STREAM_XML, $AUTH_XML, $RESOURCE_XML, $SESSION_XML, $CLOSE_XML, $START_TLS;
$fp = open_connection($options['server']);
if (!$fp) {
return false;
}
// initiates auth process (using X-FACEBOOK_PLATFORM)
send_xml($fp, $STREAM_XML);
if (!find_xmpp($fp, 'STREAM:STREAM')) {
return false;
}
if (!find_xmpp($fp, 'MECHANISM', 'X-FACEBOOK-PLATFORM')) {
return false;
}
// starting tls - MANDATORY TO USE OAUTH TOKEN!!!!
send_xml($fp, $START_TLS);
if (!find_xmpp($fp, 'PROCEED', null, $proceed)) {
return false;
}
stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
send_xml($fp, $STREAM_XML);
if (!find_xmpp($fp, 'STREAM:STREAM')) {
return false;
}
if (!find_xmpp($fp, 'MECHANISM', 'X-FACEBOOK-PLATFORM')) {
return false;
}
// gets challenge from server and decode it
send_xml($fp, $AUTH_XML);
if (!find_xmpp($fp, 'CHALLENGE', null, $challenge)) {
return false;
}
$challenge = base64_decode($challenge);
$challenge = urldecode($challenge);
parse_str($challenge, $challenge_array);
// creates the response array
$resp_array = array(
'method' => $challenge_array['method'],
'nonce' => $challenge_array['nonce'],
'access_token' => $access_token,
'api_key' => $options['app_id'],
'call_id' => 0,
'v' => '1.0',
);
// creates signature
$response = http_build_query($resp_array);
// sends the response and waits for success
$xml = '<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">'.
base64_encode($response).'</response>';
send_xml($fp, $xml);
if (!find_xmpp($fp, 'SUCCESS')) {
return false;
}
// finishes auth process
send_xml($fp, $STREAM_XML);
if (!find_xmpp($fp,'STREAM:STREAM')) {
return false;
}
if (!find_xmpp($fp, 'STREAM:FEATURES')) {
return false;
}
send_xml($fp, $RESOURCE_XML);
if (!find_xmpp($fp, 'JID')) {
return false;
}
send_xml($fp, $SESSION_XML);
if (!find_xmpp($fp, 'SESSION')) {
return false;
}
// we made it!
send_xml($fp, $CLOSE_XML);
print ("Authentication complete<br>");
fclose($fp);
return true;
}
//Gets access_token with xmpp_login permission
function get_access_token($app_id, $app_secret, $my_url){
$code = $_REQUEST["code"];
if(empty($code)) {
$dialog_url = "http://www.facebook.com/dialog/oauth?scope=xmpp_login".
"&client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url) ;
echo("<script>top.location.href='" . $dialog_url . "'</script>");
}
$token_url = "https://graph.facebook.com/oauth/access_token?client_id="
. $app_id . "&redirect_uri=" . urlencode($my_url)
. "&client_secret=" . $app_secret
. "&code=" . $code;
$access_token = file_get_contents($token_url);
parse_str($access_token, $output);
return($output['access_token']);
}
function _main() {
print "Test platform connect for XMPP<br>";
$app_id='YOUR_APP_ID';
$app_secret='YOUR-APP_SECRET';
$my_url = "YOUR_APP_URL";
$uid = 'USER_ID';
$access_token = get_access_token($app_id,$app_secret,$my_url);
print "access_token: ".$access_token."<br>";
$options = array(
'uid' => $uid,
'app_id' => $app_id,
'server' => 'chat.facebook.com',
);
// prints options used
print "server: ".$options['server']."<br>";
print "uid: ".$options['uid']."<br>";
print "app id: ".$options['app_id']."<br>";
if (xmpp_connect($options, $access_token)) {
print "Done<br>";
} else {
print "An error ocurred<br>";
}
}
_main();