Example: User login with API key using PHP

Last updated on
30 April 2025

Here is an example of a PHP script that calls the Services module's packaged XML-RPC server. This example uses the system.connect, user.login, user.logout and views.get methods. It should provide guidance for how to call web services presented by the Services module using API keys with session expiry enabled.

/**
 * IMPORTANT
 * Make sure your computer or server clock is set correctly before
 * attempting to access this web service. Time is a part of the
 * authentication process and if your clock does not match the
 * system clock, you will not be able to authenticate.
 */

/**
 * Function for generating a random string, used for
 * generating a token for the XML-RPC session
 */
function getUniqueCode($length = "") {
  $code = md5(uniqid(rand(), true));
  if ($length != "") return substr($code, 0, $length);
  else return $code;
}


// set local domain or IP address
// this needs to match the domain set when you created the API key
// it can be a straight string
$domain = $_SERVER['SERVER_NAME'];

// set API key
$kid = '35328fcd1b8cf9e101fc0e398de0be08';

// set target web service endpoint
$endpoint = 'http://www.mysite.com/services/xmlrpc';

// set the user credentials our script should login with
// we use these later on
$user_credentials = array(
  0 => 'example.user',
  1 => 'password',
);


/*
 * Firstly we touch the system.connect service
 * to open a PHP/Drupal session
 *
 * Note, this method does not require the API key
 */

// set vars for this connection
$method_name = 'system.connect';
$required_args = array();

// prepare the request
$request = xmlrpc_encode_request(
  $method_name, $required_args
);

// prepare the request context
$context = stream_context_create(
  array(
    'http' => array(
      'method' => "POST",
      'header' => "Content-Type: text/xml",
      'content' => $request,
    )
  )
);

// connect
$connect = file_get_contents($endpoint, false, $context);
// retrieve the result
$response = xmlrpc_decode($connect);

// display the result on screen
if (xmlrpc_is_fault($response)) {
    print '<h1>Error</h1>';
    trigger_error("xmlrpc: $response[faultString] ($response[faultCode])");
} else {
    // let's look at what came back
    print '<h1>Received</h1>';
    print '<pre>'. htmlspecialchars(print_r($response, true)) .'</pre>';
}


/*
 * Now we have a session, we can login to
 * retrieve our article feed
 *
 * This is our first use of the API key
 */

// set vars for this connection
$nonce = getUniqueCode("10");
$method_name = 'user.login';
$timestamp = (string) strtotime("now");
$required_args = array();

// now prepare a hash
$hash_parameters = array(
  $timestamp,
  $domain,
  $nonce,
  $method_name,
);

// create a hash using our API key
$hash = hash_hmac("sha256", implode(';', $hash_parameters), $kid);

// prepared the arguments for this service
// you can see the required arguments on the method's test page
// http://www.mysite.com/admin/build/services
$required_args = array(
  $hash,
  $domain,
  $timestamp,
  $nonce,
  $response['sessid'],
);

// any user-defined arguments for this service
// here we use the login credentials we specified at the top of the script
$user_args = $user_credentials;

// add the arguments to the request
foreach ($user_args as $arg) {
  array_push($required_args, $arg);
}

// prepare the request
$request = xmlrpc_encode_request(
  $method_name, $required_args
);

// prepare the request context
$context = stream_context_create(
  array(
    'http' => array(
      'method' => "POST",
      'header' => "Content-Type: text/xml",
      'content' => $request,
    )
  )
);

// connect
$connect = file_get_contents($endpoint, false, $context);
// retrieve the result
$response = xmlrpc_decode($connect);

// display the result on screen
if (xmlrpc_is_fault($response)) {
  print '<h1>Error</h1>';
  trigger_error("xmlrpc: $response[faultString] ($response[faultCode])");
} else {
  print '<h1>Received</h1>';
  print '<pre>'. htmlspecialchars(print_r($response, true)) .'</pre>';

  // SAVE OUR USER OBJECT - we'll need it later
  $user = new stdClass();
  $user = (object) $response['user'];

  // ALSO SAVE OUR LOGGED IN SESSID - we'll need it to logout
  // sessid changes after we login
  $loggedinsessid = $response['sessid'];
}


/*
 * Now let's retrieve the results of a view
 */

// set vars for this connection
$nonce = getUniqueCode("10");
$method_name = 'views.get';
$timestamp = (string) strtotime("now");
$required_args = array();

// now prepare a hash
$hash_parameters = array(
  $timestamp,
  $domain,
  $nonce,
  $method_name,
);

$hash = hash_hmac("sha256", implode(';', $hash_parameters), $kid);

// prepared the arguments for this service
$required_args = array(
  $hash,
  $domain,
  $timestamp,
  $nonce,
  // note, this is now the logged in sessid returned by user.login
  $response['sessid'],
);


// any user-defined arguments for this service
// you can see the required arguments on the method's test page
// http://www.mysite.com/admin/build/services
$user_args = array(
  // view name
  0 => 'subscriptions',
  // display name
  1 => 'feed_1',
  2 => array(),
  // view arguments
  3 => array((int) $user->uid),
  4 => 0,
  5 => 0,
  6 => 1,
);

// add the arguments to the request
foreach ($user_args as $arg) {
  array_push($required_args, $arg);
}

// prepare the request
$request = xmlrpc_encode_request(
  $method_name, $required_args
);

// prepare the request context
$context = stream_context_create(
  array(
    'http' => array(
      'method' => "POST",
      'header' => "Content-Type: text/xml",
      'content' => $request,
    )
  )
);

// connect
$connect = file_get_contents($endpoint, false, $context);
// retrieve the result
$response = xmlrpc_decode($connect);

// display the result on screen
if (xmlrpc_is_fault($response)) {
  print '<h1>Error</h1>';
  print '<pre>'. htmlspecialchars(print_r($response, true)) .'</pre>';  
  trigger_error("xmlrpc: $response[faultString] ($response[faultCode])");
} else {
  print '<h1>Received</h1>';
  print '<pre>'. htmlspecialchars(print_r($response, true)) .'</pre>';
}


/*
 * Finally, logout your logged in user session
 */

// set vars for this connection
$nonce = getUniqueCode("10");
$method_name = 'user.logout';
$timestamp = (string) strtotime("now");
$required_args = array();

// now prepare a hash
$hash_parameters = array(
  $timestamp,
  $domain,
  $nonce,
  $method_name,
);

$hash = hash_hmac("sha256", implode(';', $hash_parameters), $kid);

// prepared the arguments for this service
$required_args = array(
  $hash,
  $domain,
  $timestamp,
  $nonce,
  // note, this is now the sessid we saved after the user.login method above
  $loggedinsessid,
);

// prepare the request
$request = xmlrpc_encode_request(
  $method_name, $required_args
);

// prepare the request context
$context = stream_context_create(
  array(
    'http' => array(
      'method' => "POST",
      'header' => "Content-Type: text/xml",
      'content' => $request,
    )
  )
);

// connect
$connect = file_get_contents($endpoint, false, $context);
// retrieve the result
$response = xmlrpc_decode($connect);

// display the result on screen
// NOTE, in this case you may get a PHP warning, because the response
// from this method is not an array - this is a bug, but it doesn't really affect us
if (xmlrpc_is_fault($response)) {
    print '<h1>Error</h1>';
    trigger_error("xmlrpc: $response[faultString] ($response[faultCode])");
} else {
    print '<h1>Received</h1>';
    print '<pre>'. htmlspecialchars(print_r($response, true)) .'</pre>';
}

/*
 * All Done!
 */

Help improve this page

Page status: Not set

You can: