Facebook Chat Authentication in C#

Disclaimer

By viewing this webpage you have just agreed to the following; this article is not written or endorsed by Facebook, the information contained within it may or may not be accurate, your mileage may very and that I am in no way liable for your stupidity.

Updated (26 Sept '11) to include StartTls and new usage of access_token.
Updated (7 Aug '13) to include a Demo page with source (below)
Updated (Sept '13). Code was broken - now fixed!

Download the source FacebookXmpp.zip

X-Facebook-Platform mechanism

In order to authenticate with Facebook's chat platform, you need to use either DIGEST-MD5 (a hash of the users username/password - old skool) or if your application uses OAuth, then use Facebook's X-FACEBOOK-PLATFORM mechanism. I outline here how I implemented this authentication as part of the XDA Facebook for Windows Mobile application, which will include Facebook chat.

This article is a repeat of the X-FACEBOOK-PLATFORM in VB.NET article which I found to be very useful.
Credit goes to Joel Day pointing me in this direction and getting me started.

XMPP Conversation

Xmpp is basically a XML document conversation, where client and server 'build' their documents in parallel. From a coding point of view, I found it easier to write my own XML parser [yes, insane I know!] One of the main motivators behind this, is that an XMPP conversation deals in XML fragments.

Open a connection to chat.facebook.com

        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket.Connect("chat.facebook.com", 5222);

Send 'stream:stream' You initialise a conversation by opening a stream with the server. This is a "hello server" step.

<?xml version='1.0'?>
<stream:stream 
    id='1' 
    to='chat.facebook.com' 
    xmlns='jabber:client' 
    xmlns:stream='http://etherx.jabber.org/streams' 
    version='1.0' >

You should then receive a response; "hello back" followed by "list of ways to authenticate". Notice that this includes <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/> which indicates that the server supports SSL communication. There is more information which we ignore for now.

<?xml version="1.0"?>
<stream:stream 
   id="90854922" 
   from="chat.facebook.com"
   version="1.0" xmlns="jabber:client" 
   xmlns:stream="http://etherx.jabber.org/streams" xml:lang="en">

  <stream:features>
      <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
      <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
          <mechanism>X-FACEBOOK-PLATFORM</mechanism>
          <mechanism>DIGEST-MD5</mechanism>
       </mechanisms>
   </stream:features>

We switch to Transport Layer Security by continuing our plain text conversation by sending StartTLS message

   <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

The expected plain text response is

   <proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

In my Connection class code (which has 3 public methods 'Send' 'Receive' and now 'StartTls') I also have NetworkStream and a SslSocket members.

private NetworkStream _networkStream;
private SslStream _sslStream;
    
public void StartTls()
{
    UseSecure = true;

    if (_networkStream == null)
        _networkStream = new NetworkStream( _socket );

    if (_sslStream != null)
        return;

    _sslStream = new SslStream(_networkStream, false);
    _sslStream.AuthenticateAsClient("chat.facebook.com", 
      new X509CertificateCollection(), SslProtocols.Tls, false);
}

Once you have the SslStream open, use this for the reading/writing to the socket. Begin a new stream <stream:stream... as above and get new stream:features which does not include StartTls since we are using TLS.
This time we are interested the //stream:stream/stream:features/mechanisms/mechanism X-FACEBOOK-PLATFORM element.

<?xml version="1.0"?>
<stream:stream 
   id="90854922" 
   from="chat.facebook.com"
   version="1.0" xmlns="jabber:client" 
   xmlns:stream="http://etherx.jabber.org/streams" xml:lang="en">

  <stream:features>
      <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
          <mechanism>X-FACEBOOK-PLATFORM</mechanism>
          <mechanism>DIGEST-MD5</mechanism>
       </mechanisms>
   </stream:features>

Select authentication mechanism by telling the server we'll use X-Facebook-Platform authorisation.

<auth 
    xmlns='urn:ietf:params:xml:ns:xmpp-sasl' 
    mechanism='X-FACEBOOK-PLATFORM'  />

The service responds with...

<challenge
   xmlns="urn:ietf:params:xml:ns:xmppasl">
   dmVyc2lvbj0xJm1ldG....3NzlFRkJCMDVERUY2MEM=
   </challenge>

This challenge ('dmVyc2...') is a Base64 Encoded string, which we can convert to a string by doing the following

string decoded = Encoding.UTF8.GetString( Convert.FromBase64String( challengeData ) );         

Which gives us: version=1&method=auth.xmpp_login&nonce=3B53CFB6EE...FB424B68 I parse this in my code by doing a Split('&') to get three name=value pairs, then Split('=') to get name / value.
We use these to create our response which includes the following fields (in & separated name=value pairs)

  • method - the Method field received in the challenge
  • api_key - your Facebook Application key
  • access_token - the Users OAuth Access Token
  • call_id - some unique value (i.e. seconds since 1970)
  • v - the Version field received in the challenge
  • nonce - the Nonce field received in the challenge

In this new version, we no longer need the to calculate a signature. We simply covert this string into a Base64 Encoded string and pass it back to the service in a response.
Convert.ToBase64String( Encoding.UTF8.GetBytes( response ) )

<response 
   xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
   BpX2tleT1kN2Q5ZTEwODU14ZTdiYzAxY2
   EwNSZjYWxsX2lkPTEzMTM0MTQwNDEm
   ....
   bWV0aG9kPWF1dGgueG1wcF9sb2dpbiZu
   25jZT1BQzQxRjE2QTBENEI0REE3ODcX2tlx
   </response>

Assuming that your user has permitted xmpp_login permission during the OAuth process, you should get the response

<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

Now you're ready to actually do something with the service!

Update August 2013

Since a few people seem to have problems with getting started with this code I've made a very quick and dirty web application. You can try a demo in Quigley's Lab and download the source code for that lab.

NO SUPPORT COMMENTS
Feel free to comment below, but DO NOT expect answers to any questions. If you want WORKING CODE please visit the XDA Facebook project mentioned above and see my code there.

Copyright © 2009-2013 Ian Quigley
Advert
blog comments powered by Disqus