2 Legged OAuth in PHP


Google Apps Premier/Education administrators can take advantage of 2 legged OAuth to communicate with the Google Data APIs. This sample makes use of the PHP OAuth library from oauth.net.
<?php
require_once('OAuth.php');

// Establish an OAuth consumer based on our admin 'credentials'
$CONSUMER_KEY = 'yourdomain.com'; 
$CONSUMER_SECRET = 'YOUR_CONSUMER_SECRET'; 
$consumer = new OAuthConsumer($CONSUMER_KEY, $CONSUMER_SECRET, NULL);

// Setup OAuth request based our previous credentials and query
$user= 'any.user@yourdomain.com';
$base_feed = 'http://www.google.com/m8/feeds/contacts/default/full/';
$params = array('max-results' => 10, 'xoauth_requestor_id' => $user);
$request = OAuthRequest::from_consumer_and_token($consumer, NULL, 'GET', $base_feed, $params);

// Sign the constructed OAuth request using HMAC-SHA1
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, NULL);

// Make signed OAuth request to the Contacts API server
$url = $base_feed . '?' . implode_assoc('=', '&', $params);
echo send_request($request->get_normalized_http_method(), $url, $request->to_header());
 
/**
 * Makes an HTTP request to the specified URL
 * @param string $http_method The HTTP method (GET, POST, PUT, DELETE)
 * @param string $url Full URL of the resource to access
 * @param string $auth_header (optional) Authorization header
 * @param string $postData (optional) POST/PUT request body
 * @return string Response body from the server
 */
function send_request($http_method, $url, $auth_header=null, $postData=null) {
  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_FAILONERROR, false);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

  switch($http_method) {
    case 'GET':
      if ($auth_header) {
        curl_setopt($curl, CURLOPT_HTTPHEADER, array($auth_header)); 
      }
      break;
    case 'POST':
      curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/atom+xml', 
                                                   $auth_header)); 
      curl_setopt($curl, CURLOPT_POST, 1);                                       
      curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
      break;
    case 'PUT':
      curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/atom+xml', 
                                                   $auth_header)); 
      curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
      break;
    case 'DELETE':
      curl_setopt($curl, CURLOPT_HTTPHEADER, array($auth_header)); 
      curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); 
      break;
  }
  $response = curl_exec($curl);
  if (!$response) {
    $response = curl_error($curl);
  }
  curl_close($curl);
  return $response;
}

/**
 * Joins key:value pairs by inner_glue and each pair together by outer_glue
 * @param string $inner_glue The HTTP method (GET, POST, PUT, DELETE)
 * @param string $outer_glue Full URL of the resource to access
 * @param array $array Associative array of query parameters
 * @return string Urlencoded string of query parameters
 */
function implode_assoc($inner_glue, $outer_glue, $array) {
  $output = array();
  foreach($array as $key => $item) {
    $output[] = $key . $inner_glue . urlencode($item);
  }
  return implode($outer_glue, $output);
}
?>

37 comments:

Javier Alvarez said...

Great example !!
Could you post another php example (or link) to add a new contact using HTTP POST ?
I'm trying, but I have problems :-(
Thanks in advance.
Regards.

Eric (Google) said...

The Contacts API is not supported in the Zend PHP client library, but you can send over raw XML. You can use the example @ http://code.google.com/apis/contacts/developers_guide_protocol.html#Creating for $contactEntry.

// setup same as before
params = array('xoauth_requestor_id' => $user);
$request = OAuthRequest::from_consumer_and_token($consumer, NULL, 'POST', $base_feed, $params);
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, NULL);

$url = $base_feed . '?' . implode_assoc('=', '&', $params);
echo send_request($request->get_normalized_http_method(), $url, $request->to_header(), $contactEntry);

Javier Alvarez said...
This comment has been removed by the author.
Javier Alvarez said...

Thanks for your help!!
I was not using the parameters properly. I had to use another $base_feed and I used and access_token (previously autorized by user). Something like this:

$CONSUMER_KEY = 'yourdomain.com';
$CONSUMER_SECRET = 'YOUR_CONSUMER_SECRET';
$consumer = new OAuthConsumer($CONSUMER_KEY, $CONSUMER_SECRET, NULL);
$token = new OAuthConsumer($access_token, $access_token_secret);
$user= 'any.user@yourdomain.com';
$url_base = "http://www.google.com/m8/feeds/contacts/".urlencode($user)."/full";
$request = OAuthRequest::from_consumer_and_token($consumer, $token, 'POST', $url_base, $params);
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, $token);
$url = $url_base . '?' . implode_assoc('=', '&', $params);
echo send_request($request->get_normalized_http_method(), $url, $request->to_header());

Eric (Google) said...

Just so anyone following knows, Javier's code is correct, but uses 3 Legged OAuth instead of 2 Legged. With 2 Legged OAuth, there's no access token.

See http://code.google.com/apis/accounts/docs/OAuth.html#GoogleAppsOAuth

Owen said...

If anyone has an example for how this can be used I'd love to see it. I'm not sure I really understand what the potential uses are.

Eric (Google) said...

This page lists use cases:
http://code.google.com/apis/accounts/docs/OAuth.html#GoogleAppsOAuth

For example, as a domain admin you could up load an HR document to every users' Google Docs account, add/update a particular business contact, or add a company event to their Calendar. That's all without their prior approval.

Sirhc Senots said...

Hey Eric what license is this example code posted under?

Eric (Google) said...

Apache 2.0 License

Eric said...

Hi,

Nice, It's working very well...
Can I use it to list the last unread messages ?
I didn't find it yet...

Thanks
Éric (but another !)

Eric (Google) said...

If you're asking about the Gmail Atom feed + 2 legged oauth, the answer is no.

http://code.google.com/p/gdata-issues/issues/detail?id=1264

Eric said...

Thanks for your answer...
Looking for that a few hours today...
And I didn't yet find how to print unread mail list in a php page without having the user password writing clearly... (with Oauth for exemple)

If you have some idea...

Thanks again
Éric (NOT the google one ;-) )

Hubert said...

this code does not work with the calendar.

I think that the calendar does not work wiht OAuth at all. I always get the same message: "Unknown authorization header" (Error code 401)

I tested 3-legged OAuth.

Would you mind to test calendar with your code? Thanks




By the way, useful for curl connector would be to use following to follow redirects:
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);

Eric (Google) said...

Ah yes, I'm always careful not to use Calendar in OAuth examples. :)

I believe the issue is the 302 redirect Calendar returns (if you don't include a gsessionid). You'll need to re-issue the request with the URL calendar returns in the redirect. This code does not resign the redirect request.

Hubert said...

> I believe the issue is the 302 redirect
> Calendar returns (if you don't include
> a gsessionid). You'll need to re-issue
> the request with the URL calendar
> returns in the redirect. This code does
> not resign the redirect request.

Sorry, did I understand you correctly:
Calendar works/should work with gsession in the url?

I am doing that but no success:
[request] => GET /calendar/feeds/default/allcalendars/full?gsessionid=lmeVZfrpWnoUz-RlEfBafg? HTTP/1.0
Authorization: OAuth realm="",
oauth_consumer_key="www.example.com",
oauth_nonce="e4287b9e5a18b403c51bc9d21ac64f7a",
oauth_signature="9vmOxdfGAF9%2FV9%2BXDlM4gyE7VXM%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1255082495",
oauth_token="1%2FsxeOZWLy8nN8Tbt0lVAeR2ATiaQZnWPB51nTvo8n9Sw",
oauth_version="1.0"
Accept: application/atom+xml, text/html; q=0.3, application/xhtml+xml; q=0.5
Content-Type: application/x-www-form-urlencoded
Host: www.google.com
Accept-Language: en,en-us;q=0.8,de;q=0.7,de-de;q=0.5,bs;q=0.3,sr;q=0.2
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Content-Length: 0


answer:
Unknown authorization header
Error 401


Thanks

Hubert said...

my mistake.

I resigned it and everything was perfect.

Thanks for the hint

Pork Chop said...

How can I take the $request (in the example) after signing and use it as an httpClient with Zend_Gdata? All of the Gdata functions require a $client and I'd like to use one that has been authenticated with this type of 2 legged Oauth. Thanks.

Eric (Google) said...

Check out this sample:
http://code.google.com/p/gdata-samples/source/browse/trunk/hybrid/index.php#106

Whiz-Solutions said...

Hi All,

Thanks for sharing the example, but when trying to run the code I am getting Token invalid - Invalid AuthSub token. Error 401.

I have registered my application on google and am using the consumer key and secret given to me.

Can anyone help me out?

Thanks,
Anil

Алексей Руденко said...

Hello,
thanks for example! But there's one questions - how can I retrieve contact emails? They are not displayed currently - I can get only contact names.
Thanks a lot

Reese said...

"I resigned it and everything was perfect".

How do you re-sign it? Where do you get the URL calendar returns?

Daniel Gleckler said...

If I wanted to POST a document/image file up using this method, how would I format my $postData?

I'm getting a "Content is not allowed in prolog." response from the server if I just pass $_FILES['myfile'];

Mohd said...

I am getting Token invalid - Invalid AuthSub token. Error 401.


What's going wrong?

Francois said...

So line 10 to 16 must be executed before EACH command to the API ?

madhuri said...

It was a great example my fren.I was trying out a lot with many PHP examples but I haven't succeeded with the coding.In web design company had made with reference to Javier's code using 3 legged OAuth.

sunitha said...

Several things in here' haven't considered before.Thank you for making this type of awesome publish that is really perfectly written, is going to be mentioning lots of buddies relating to this. Maintain blogging. joomla websites | joomla development

Lalit said...

hey buddy i want to implement google calendar by using this code.. so what changes is needed to implement google calendar to fetch feeds data

Anonymous said...

It is not working at alll

Anonymous said...

The code is not working at all!!!!!! Giving error

Anonymous said...

401. That's an error.is showing

Anonymous said...

please help!!!!!!!!!!!!!! I am getting the following error


{"version":"2","status":"error","error":"Your sort parameter cannot be parsed. Please see http:\/\/wiki.developer.factual.com\/Server-API for documentation.","error_type":"Api::Error::InvalidArgument"}

Azadi said...

Just used this code as a base to add owners to about 1000 Google sites under our school domain - worked a treat!

However, updating ACL entries (PUT requests) kept failing. I had to add If-Match:* header to the requests by modifying the corresponding line of send_request() function to:

curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/atom+xml', 'If-Match:*', $auth_header));

kosovohp said...

Girl Xinh | Hot Girl | Cute Girl | Sexy Girl | Hot Girl Asian
Hot Girl | Lexi Belle | Sexy Girl | Cute Girl | Hot Asian Girl | Leah Dizon | Hot Girl Asian | Girl Xinh
socks proxy | socks5 | proxy free |proxy list

epictoon said...

So that is how you simply do it. .... Thanks for the code :)
delicious


Cisgirin said...
This comment has been removed by the author.
ansley dias said...

how can we use this to fetch calendars?

martid95 said...

Someone can add a new email to gmail contacts using OAuth 2.0 and PHP?