Integrating FBOAuth with Services

Everyone loves the Services module. It allows you to easily create API endpoints for Drupal's core features, permitting you to interact with Drupal from external applications. It also very easily extended.

Among its many default resources, Services offers a user.login method that allows external applications to authenticate via Drupal. I'm going to share a quick snippet that will permit you to extend Services so that it allows your users to login via Facebook (leveraging the FBOauth module).

Start by downloading and enabling Services and Fboauth. Then, create a custom module to house your code. Your module's info file should specify services and fboauth as requirements.

<?php
name = Services FBOauth
description = Provides FBOAuth integration for the Services module.
package = services
core = 7.x

dependencies[] = services
dependencies[] = fboauth
?>

Easy enough. Now let's use Service's hook_services_resources() function to define a new resource.

<?php
/**
 * Implements hook_services_resources().
 */
function services_fboauth_services_resources() {
  $definition['fboauth']['actions']['connect'] = array(
    'help' => 'Login a user for a new session via FBOAuth',
    'callback' => 'services_fboauth_connect',
    'args' => array(
      array(
        'name' => 'access_token',
        'type' => 'string',
        'description' => 'A valid Facebook access token',
        'source' => 'data',
        'optional' => FALSE,
      ),
    ),
    // The services module says this about services_access_menu: 
    // "If you think you need it you are almost certainly wrong."
    // But I think that this is one of those rare exceptions.
    'access callback' => 'services_access_menu',
  );

  return $definition;
}
?>

Here, we've defined a new resource type "fboauth." We've also defined a new action for that resource, labeled 'connect'. This will be available at /your_endpoint_path/fboauth/connect.

Now let's define the services_fboauth_connect() callback that makes the magic happen.

<?php
/**
 * Allow FBOAUTH login via services.
 *
 * @param $data,
 *   An associative array containing:
 *   - access_token: a valid Facebook access token (not access code).
 *     The requesting application must have already gone through the 
 *     process of requesting permissions, getting access code, requesting
 *     access token, etc.
 *
 * @return
 *   A valid session object, just like _user_resource_login().
 */
function services_fboauth_connect($data) {
  if ($user->uid) {
    // user is already logged in
    return services_error(t('Already logged in as @user.', array('@user' => $user->name)), 406);
  }

  // Include fboauth functions as required.
  module_load_include('inc', 'fboauth', 'includes/fboauth.fboauth');
  $access_token = $data['access_token'];
  $app_id       = variable_get('fboauth_id', '');

  // Find Drupal user that corresponds with this Facebook user.
  $fbuser = fboauth_graph_query('me', $access_token);
  $uid = fboauth_uid_load($fbuser->id);
  if ($user = user_load($uid)) {
    if ($user->status) {
      // Much of the login logic was taken from _user_resource_login().
      user_login_finalize();

      $return = new stdClass();
      $return->sessid = session_id();
      $return->session_name = session_name();

      services_remove_user_data($user);

      $return->user = $user;

      return $return;
    }
    else {
      $message = t('The username %name has not been activated or is blocked.', array('%name' => $account->name));
    }
  }
  else {
    $message = t('Error: no Drupal account was found for the specified Facebook user');
  }

  watchdog('services_fboauth', $message);
  return services_error($message, 401);
}
?>

To use this function, your external application must POST a valid 'access_token' to /your_endpoint_path/fboauth/connect. The endpoint will then return a valid session object, identical to the one posted by the default user.login method.

That's all there is to it!

Seems like genius plan.. Why not publish it at Drupal.org? I was looking this solution and just planned to build for D6 it just before I found yours.

In reply to by Kaido Toomingas

I did added also second argument facebook user id and replaced $fbuser = fboauth_graph_query('me', $access_token); with $fbuser = fboauth_graph_query($fb_userid, $access_token);
becouse the user I did use this to access the api from mobile app.

I have created https://drupal.org/node/2087363 with minor tweaks please create an issue for further improvements.

Can someone please share a sample implementation of this module? I am looking for 2 things - ability to create a new account and then authenticating the user .

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.