You can make authenticated requests to REST Server using standard Drupal session-based security with no effort on your part. This is managed through session cookies. However when doing this from code (for instance when using drupal_http_request() or cURL), you may need to go through some extra work and set the cookie header by hand. The cookie header looks like this:
Cookie: SESS5913ad7ed2adf92cab1103dad2f5596c=213d28535c6972e16430a4e1e03ce7ea
This has three parts. The head identifier ('Cookie'), the session name ('SESS5913ad7ed2adf92cab1103dad2f5596c'), and the session id ('213d28535c6972e16430a4e1e03ce7ea'). Thankfully, when you call the user/login resource in Services, both the session name and session id are part of the response object, so it is pretty easy to put this header together and return it with the next request. Once you've done that, the next request will act under the authorized user's session.
Here is some sample code that demonstrates this. To set this up you will need a Drupal installation setup with an endpoint that has the user/login and node/retrieve resources enabled, and which does not give the anonymous user 'access content' restrictions.
Example: Drupal 7
Tested against 7.x-3.0-rc1.
<?php
$base_url = 'http://localhost/test_endpoint';
$data = array(
'username' => 'admin',
'password' => 'password',
);
$data = drupal_json_encode($data);
$options = array(
'headers' => array(
'Content-Type' => 'application/json',
),
'method' => 'POST',
'data' => $data
);
$response = drupal_http_request($base_url . '/user/login', $options);
$data = json_decode($response->data);
// Check if login was successful
if ($response->code == 200) {
// Now recycle the login cookie we received in the first request
$options['headers']['Cookie'] = $data->session_name . '=' . $data->sessid;
// Get info about a user
$data = array();
$options['data'] = http_build_query($data, '', '&');
$options['method'] = 'GET';
$response = drupal_http_request($base_url . '/user/32', $options);
}
?>
Parameters for drupal_http_request have changed in Drupal 7. Services 3 have different user login variables that need to be POSTed between each version of Drupal.
Example: Drupal 6
Tested against 6.x-3.0-beta2.
<?php
// This is the base URL for our installation
$base_url = 'http://domain.com/test_endpoint/';
// necessary or the response is empty:
$headers = array('Content-Type' => 'application/x-www-form-urlencoded');
// Login
$data = array(
'username' => 'admin',
'password' => 'password',
);
$data = http_build_query($data, '', '&');
$response = drupal_http_request($base_url . '/user/login', $headers, 'POST', $data);
$data = json_decode($response->data);
//$headers['Cookie'] = "$data->session_name=$data->sessid";
$response = drupal_http_request($base_url . '/node/21.json', $headers); // replace this with a node id on your system
print_r(json_decode($response->data));
?>
Note that the line which sets the cookie header is commented out. If you run this code you will get access denied when you try and access node 21 . Now uncomment the cookie header line and run again. It works! You can save the session name and session id somewhere convenient and use it for all future calls as needed.
This same method can be used in Drupal 7 to make authenticated calls via XMLRPC. In Drupal 6 this is not possible without this core patch.
Note that most cookies have expirations or may only be active for one session. You should respect these limitations and take them into account when building your system (although doing so is beyond the scope of this code sample.)
Comments
Missing $headers
From http://plosquare.blogspot.com/2010/03/solution-for-post-empty-after.html
Posting form data to a Services implemented resource
When using REST server, and having written a resource that implements Create, the Services 3.0 handling of POST data puts an additional wrapper around the data. For example, if you have a resource whose Create expects data like this:
Then the logic to POST that is:
In the http_build_query() call, you'll notice the POST data getting an additional array wrapper. Without that additional data wrapper, the response code from drupal_http_request() is 406, 'Not Acceptable'.
-Blake
www.BlakeSenftner.com www.3D-Avatar-Store.com
$data array has wrong key names to login
The service module (user_resource.inc) and also the user form has the form names 'name' and 'pass' defined and not 'username' and 'password'.
When I change this names, the example above works perfect!
Which version of Services are
Which version of Services are you using?
In the Services 3.x-dev version, Feb 2011, file user_resource.inc: "login" is defined with the parameter names "username" and "password":
-Blake
www.BlakeSenftner.com www.3D-Avatar-Store.com
I'm using 6.x-3.0-beta2 as
I'm using 6.x-3.0-beta2 as described in the example and this version uses pass and name. It's also correct, that the dev/head revision use username and password.
I will update my code after upgrading to the next beta/rc version. :-)
Thanks,
Thomas
Thx for the working d6 example
Thx for sharing this working d6 example.I am working on this for hours and here is your solution!
Some php curl scripts
Hi, here are some php *client* scripts that don't use Drupal. This may be helpful if you are integrating with another system. Done with Services 7.x-3.x-rc3 using Quickstart 1.0.
Login.php
authenticated_request.php
logout.php
Appreciated Michael Cole,
Appreciated Michael Cole, yours was the first script that I was able to cut and paste and make it work right out of the box.
My Drupal sites:
Works perfectly!! Thanks
Thanks Michael Cole! Your is the only example I could get working right away.
To create a node with custom fields, we can use following code.
Getting Access denied for user anonymous Error
hi,
I am getting Access denied for user anonymous Error even if am passing the header cookie. Can any one please help me.
I have the same problem
I have the same problem sarath.rajan. any suggestions ?
add CSRF token request
Thanks for the example, MichaelCole.
To get this working with the lastest version of Services I had to add a CSRF token request - token.php
You need to run this after logging in, then all subsequent requests need to fetch the CSRF token and add it as a header:
------------------
Phil Dodd
twitter: @phildoddau
I am not sure why the cookie
I am not sure why the cookie line is commented out in the drupal 6 exmaple, but this is my working code (getting user information, not node info):
I tried to use Michael Cole
I tried to use Michael Cole example, but it don't really worked for me... I just changed the $service_url and the $post_data values. If I try to access other resource like /rest/user/1 it worked fine. What can be wrong?
where to put the d6
where to put the d6 example?
In a module or in a php- file in Drupal directory?
Do you need to kill the session or logout, after doing stuff with rest?
Cookies not being sent
Apparently the login REST endpoint does not send the cookie anymore.
Just upgrade one of our servers to Drupal 7.17 and Services to 7.x-3.2 and suddenly the REST login endpoint does not send the cookie HTTP header.
Issue has been opened.
Session
If you make a request on server.com and you are already login on it (server.com), is there any way to retrieve session or you must always ask to login.
For example I go on server.com, Im login, I go on client.com, I must login again on server.com?
(cause I try and global $user on server.com side is always anonymous).
any update on getting session details
Were you ale to get the logged in session details on client.com. Am looking into a scenario where a user may login to drupal site and a client site on the same browser, and trying to post data onto drupal site thru services. Right now I am asking the user to enter their drupal credentials on client site even when they logged onto drupal site on the same browser.
For site installed in subdirectory
Uncomment the $cookie_domain variable in 'sites/default/settings.php'
and set it to your site's root:
$cookie_domain = 'mysite.com';
reference: http://yuriybabenko.com/blog/drupals-domain-access-and-sites-in-subfolders