Skip to content
Alex Koppel edited this page Feb 28, 2017 · 8 revisions

Tired of polling Facebook’s server’s for the latest data about your users? Poll no more! The Graph API supports real-time updates that POST to your servers whenever Facebook data you care about changes. Once notified, you can decided how and when to fetch the new, updated data from Facebook.

Facebook supports subscriptions to the objects such as users, permissions, pages, and errors, and are actively expanding support. To get the most up to date information on which objects and connections are available for realtime updates, check out the official Facebook real-time update documentation.

RealtimeUpdates Class

Koala supports real-time updates with the RealtimeUpdates class, which contains everything you need to add, update, read and delete your subscriptions to real-time updates.

A RealtimeUpdates object can be create in one of two ways. Either pass in your app ID and your applications secret:

@updates = Koala::Facebook::RealtimeUpdates.new(:app_id => YOUR_APP_ID, :secret => YOUR_APP_SECRET)

Or pass in your app ID and an access token for your application:

@updates = Koala::Facebook::RealtimeUpdates.new(:app_id => YOUR_APP_ID, :app_access_token => YOUR_ACCESS_TOKEN)

(Check out the OAuth documentation for more information on getting an app’s access token.)

Listing Your Current Subscriptions

@updates.list_subscriptions
# => [{"object" => "user", ...}, {"object" => "permissions"}, ...]

Adding or Modifying Your Subscriptions

@updates.subscribe("user", "first_name, last_name", YOUR_CALLBACK_URL, YOUR_VERIFY_TOKEN)
# => true

Remember that before Facebook will respond to your subscription request, it will verify the given callback URL. We’ll get to how to validate your callback URL with Koala a little later.

Note: If your callback URL points to the same server from which you are adding/updating a subscription, be sure that your server can handle at least two requests at the same time. If not, Facebook will not be able to verify the callback URL due to your server being busy. For example, this can happen if you expose an admin-only interface in your application through which you manage your real-time update subscriptions.

Deleting a subscription

@updates.unsubscribe("user")
# => true

Verifying Your Callback URL

Before adding or updating a subscription completes, Facebook will send a GET request to the added/updated subscription’s callback URL. In response, your application must check that the given verify token matches the verify token used when adding/updating a subscription and, if so, return the given challenge.

Verifying the token

Koala provides the static meet_challenge method to take care of most of the details with verifying your callback URL. Depending on what you used as the verify_token when adding/updating your subscription, you can use meet_challenge in a couple different ways.

If you know what the value of the verify_token should be, you can just pass it in directly:

# Assume @params is a hash of the parameters of the request
Koala::Facebook::RealtimeUpdates.meet_challenge(@params, YOUR_VERIFY_TOKEN)

If you sent a specially constructed value for verify_token when adding/updating your subscription (such as a hash of various values), you can pass meet_challenge a block (which takes a token as its only parameter) and meet_challenge will only verify the token if the block returns true.

Koala::Facebook::RealtimeUpdates.meet_challenge(@params) do |token|
  # Your token verifying code
end

If the token is valid, meet_challenge will return the challenge value in the given params, and if not returns false.

Verifying Updates

As a security measure, all updates from facebook are signed using X-Hub-Signature: sha1=XXXX where XXX is the SHA1 of the JSON payload (using your application secret as the key). You can validate these using validate_update in a controller method, for instance with @realtime_updates being an instance of Koala::Facebook::RealtimeUpdates:

def receive_update
  if @realtime_updates.validate_update(request.body, headers)
    # process update from request.body
  else
    render text: "not authorized", status: 401
  end
end