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.
<span style="color: #000000"><span style="color: #0000BB"><?php<br>name </span><span style="color: #007700">= </span><span style="color: #0000BB">Services FBOauth<br>description </span><span style="color: #007700">= </span><span style="color: #0000BB">Provides FBOAuth integration </span><span style="color: #007700">for </span><span style="color: #0000BB">the Services module</span><span style="color: #007700">.<br></span><span style="color: #0000BB">package </span><span style="color: #007700">= </span><span style="color: #0000BB">services<br>core </span><span style="color: #007700">= </span><span style="color: #0000BB">7.x<p>dependencies</p></span><span style="color: #007700">[] = </span><span style="color: #0000BB">services<br>dependencies</span><span style="color: #007700">[] = </span><span style="color: #0000BB">fboauth<br>?></span></span>
Easy enough. Now let's use Service's hook_services_resources() function to define a new resource.
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #FF8000">/**<br> * Implements hook_services_resources().<br> */<br></span><span style="color: #007700">function </span><span style="color: #0000BB">services_fboauth_services_resources</span><span style="color: #007700">() {<br> </span><span style="color: #0000BB">$definition</span><span style="color: #007700">[</span><span style="color: #DD0000">'fboauth'</span><span style="color: #007700">][</span><span style="color: #DD0000">'actions'</span><span style="color: #007700">][</span><span style="color: #DD0000">'connect'</span><span style="color: #007700">] = array(<br> </span><span style="color: #DD0000">'help' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'Login a user for a new session via FBOAuth'</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'callback' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'services_fboauth_connect'</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'args' </span><span style="color: #007700">=> array(<br> array(<br> </span><span style="color: #DD0000">'name' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'access_token'</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'type' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'string'</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'description' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'A valid Facebook access token'</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'source' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'data'</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'optional' </span><span style="color: #007700">=> </span><span style="color: #0000BB">FALSE</span><span style="color: #007700">,<br> ),<br> ),<br> </span><span style="color: #FF8000">// The services module says this about services_access_menu: <br> // "If you think you need it you are almost certainly wrong."<br> // But I think that this is one of those rare exceptions.<br> </span><span style="color: #DD0000">'access callback' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'services_access_menu'</span><span style="color: #007700">,<br> );<p> return </p></span><span style="color: #0000BB">$definition</span><span style="color: #007700">;<br>}<br></span><span style="color: #0000BB">?></span></span>
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.
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #FF8000">/**<br> * Allow FBOAUTH login via services.<br> *<br> * @param $data,<br> * An associative array containing:<br> * - access_token: a valid Facebook access token (not access code).<br> * The requesting application must have already gone through the <br> * process of requesting permissions, getting access code, requesting<br> * access token, etc.<br> *<br> * @return<br> * A valid session object, just like _user_resource_login().<br> */<br></span><span style="color: #007700">function </span><span style="color: #0000BB">services_fboauth_connect</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">) {<br> if (</span><span style="color: #0000BB">$user</span><span style="color: #007700">-></span><span style="color: #0000BB">uid</span><span style="color: #007700">) {<br> </span><span style="color: #FF8000">// user is already logged in<br> </span><span style="color: #007700">return </span><span style="color: #0000BB">services_error</span><span style="color: #007700">(</span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Already logged in as @user.'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'@user' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$user</span><span style="color: #007700">-></span><span style="color: #0000BB">name</span><span style="color: #007700">)), </span><span style="color: #0000BB">406</span><span style="color: #007700">);<br> }<p> </p></span><span style="color: #FF8000">// Include fboauth functions as required.<br> </span><span style="color: #0000BB">module_load_include</span><span style="color: #007700">(</span><span style="color: #DD0000">'inc'</span><span style="color: #007700">, </span><span style="color: #DD0000">'fboauth'</span><span style="color: #007700">, </span><span style="color: #DD0000">'includes/fboauth.fboauth'</span><span style="color: #007700">);<br> </span><span style="color: #0000BB">$access_token </span><span style="color: #007700">= </span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'access_token'</span><span style="color: #007700">];<br> </span><span style="color: #0000BB">$app_id </span><span style="color: #007700">= </span><span style="color: #0000BB">variable_get</span><span style="color: #007700">(</span><span style="color: #DD0000">'fboauth_id'</span><span style="color: #007700">, </span><span style="color: #DD0000">''</span><span style="color: #007700">);<br> <br> </span><span style="color: #FF8000">// Find Drupal user that corresponds with this Facebook user.<br> </span><span style="color: #0000BB">$fbuser </span><span style="color: #007700">= </span><span style="color: #0000BB">fboauth_graph_query</span><span style="color: #007700">(</span><span style="color: #DD0000">'me'</span><span style="color: #007700">, </span><span style="color: #0000BB">$access_token</span><span style="color: #007700">);<br> </span><span style="color: #0000BB">$uid </span><span style="color: #007700">= </span><span style="color: #0000BB">fboauth_uid_load</span><span style="color: #007700">(</span><span style="color: #0000BB">$fbuser</span><span style="color: #007700">-></span><span style="color: #0000BB">id</span><span style="color: #007700">);<br> if (</span><span style="color: #0000BB">$user </span><span style="color: #007700">= </span><span style="color: #0000BB">user_load</span><span style="color: #007700">(</span><span style="color: #0000BB">$uid</span><span style="color: #007700">)) {<br> if (</span><span style="color: #0000BB">$user</span><span style="color: #007700">-></span><span style="color: #0000BB">status</span><span style="color: #007700">) {<br> </span><span style="color: #FF8000">// Much of the login logic was taken from _user_resource_login().<br> </span><span style="color: #0000BB">user_login_finalize</span><span style="color: #007700">();<p> </p></span><span style="color: #0000BB">$return </span><span style="color: #007700">= new </span><span style="color: #0000BB">stdClass</span><span style="color: #007700">();<br> </span><span style="color: #0000BB">$return</span><span style="color: #007700">-></span><span style="color: #0000BB">sessid </span><span style="color: #007700">= </span><span style="color: #0000BB">session_id</span><span style="color: #007700">();<br> </span><span style="color: #0000BB">$return</span><span style="color: #007700">-></span><span style="color: #0000BB">session_name </span><span style="color: #007700">= </span><span style="color: #0000BB">session_name</span><span style="color: #007700">();<p> </p></span><span style="color: #0000BB">services_remove_user_data</span><span style="color: #007700">(</span><span style="color: #0000BB">$user</span><span style="color: #007700">);<p> </p></span><span style="color: #0000BB">$return</span><span style="color: #007700">-></span><span style="color: #0000BB">user </span><span style="color: #007700">= </span><span style="color: #0000BB">$user</span><span style="color: #007700">;<p> return </p></span><span style="color: #0000BB">$return</span><span style="color: #007700">;<br> }<br> else {<br> </span><span style="color: #0000BB">$message </span><span style="color: #007700">= </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'The username %name has not been activated or is blocked.'</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'%name' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$account</span><span style="color: #007700">-></span><span style="color: #0000BB">name</span><span style="color: #007700">));<br> }<br> }<br> else {<br> </span><span style="color: #0000BB">$message </span><span style="color: #007700">= </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Error: no Drupal account was found for the specified Facebook user'</span><span style="color: #007700">);<br> }<p> </p></span><span style="color: #0000BB">watchdog</span><span style="color: #007700">(</span><span style="color: #DD0000">'services_fboauth'</span><span style="color: #007700">, </span><span style="color: #0000BB">$message</span><span style="color: #007700">);<br> return </span><span style="color: #0000BB">services_error</span><span style="color: #007700">(</span><span style="color: #0000BB">$message</span><span style="color: #007700">, </span><span style="color: #0000BB">401</span><span style="color: #007700">);<br>}<br></span><span style="color: #0000BB">?></span></span>
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!
7.x,
drupal, fboauth, services, snippet