Search code examples
phpzend-frameworkoauthzend-gdatagoogle-contacts-api

"Unknown authorization header" while fetching google contacts using php, (zend) gdata and 2 legged oauth


I am writing a 2 Legged OAuth app (Google Marketplace app) using zend gdata library. I need to fetch google contacts.

Code as given below.

require_once 'Zend/Oauth/Consumer.php';
$oauthOptions = array(
    'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
    'version' => '1.0',
    'signatureMethod' => 'HMAC-SHA1',
    'consumerKey' => $CONSUMER_KEY,
    'consumerSecret' => $CONSUMER_SECRET
);

$consumer = new Zend_Oauth_Consumer($oauthOptions);
$token = new Zend_Oauth_Token_Access();
$httpClient = $token->getHttpClient($oauthOptions);

$url = 'http://www.google.com/m8/feeds/contacts/default/full';

require_once 'Zend/Gdata/Gapps.php';
$gdata = new Zend_Gdata($httpClient);

require_once 'Zend/Gdata/Query.php';
require_once 'Zend/Gdata/Feed.php';
require_once 'Zend/Gdata/App.php';

$query = new Zend_Gdata_Query($url);
try {
    $feed = $gdata->getFeed($query);
} catch(Zend_Gdata_App_Exception $ex){
    print_r($ex->getMessage());
}

I get following error:

Expected response code 200, got 401
Unknown authorization header
Error 401



HTTP headers sent on executing above code are:

GET /m8/feeds/contacts/default/full HTTP/1.1
Host: www.google.com
Connection: close
User-Agent: MyCompany-MyApp-1.0 Zend_Framework_Gdata/1.11.0dev
Accept-encoding: identity
Authorization: OAuth realm="",oauth_consumer_key="686518909188.apps.googleusercontent.com",oauth_nonce="fc99e10f42cdb01c7f3ce1ab2775e616",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1316583946",oauth_version="1.0",oauth_signature="hlbTvPExy4r4%2FyY1ddEsy1AJhf4%3D"

HTTP Response received:

HTTP/1.1 401 Unknown authorization header
Content-Type: text/html; charset=UTF-8
Date: Wed, 21 Sep 2011 05:45:47 GMT
Expires: Wed, 21 Sep 2011 05:45:47 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Connection: close

<HTML>
<HEAD>
<TITLE>Unknown authorization header</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unknown authorization header</H1>
<H2>Error 401</H2>
</BODY>
</HTML>


Please let me know what am I missing here.


Solution

  • It appears that the "xoauth_requestor_id" request parameter is not being set when using 2-legged OAuth (xoauth).

    I tried setting this query parameter on the HttpClient object that is passed to the Zend_Gdata_Calendar constructor:

    $httpClient->setParameterGet('xoauth_requestor_id', $userEmail);
    

    But unfortunately this clean approach didn't work. Seems that the Zend_GData_Calendar class isn't fully utilising the injected HttpClient object.

    So I've resorted to extending Zend_GData_Calendar and instantiating my customised version of it instead. I've not fully tested all the functionality but here is what I have so far and it can easily be built upon:

    /**
     * Slightly modified class which extends Zend_Gdata_Calendar. Fixes a problem with the request URI when using 2-legged
     * OAuth (xoauth). Adds on the xoauth_requestor_id query parameter.
     */
    class Xoauth_Gdata_Calendar extends Zend_Gdata_Calendar {
        protected $requestorId;
    
        /**
         * Set the xoauth_requestor_id for requests
         *
         * @param string $requestorId
         */
        public function setRequestorId($requestorId) {
            $this->requestorId = $requestorId;
        }
    
        /**
         * Get the currently set xoauth_requestor_id
         *
         * @return string
         */
        public function getRequestorId() {
            return $this->requestorId;
        }
    
        /**
         * {@inheritdoc} extended to also include the xoauth_requestor_id query parameter in the request URI. This fixes
         * an authentication issue when using 2-legged OAuth (xoauth).
         *
         * @return string|Zend_Gdata_App_Feed
         */
        public function getCalendarListFeed() {
            $uri = self::CALENDAR_FEED_URI . '/default';
            if($this->requestorId) {
                $uri .= '?xoauth_requestor_id=' . urlencode($this->requestorId);
            }
    
            return parent::getFeed($uri,'Zend_Gdata_Calendar_ListFeed');
        }
    }
    

    Then to use this you instantiate this class rather Zend_Gdata_Calendar base class. You just need to call setRequestorId($usersEmail), for example:

    $calendarClient = new Xoauth_Gdata_Calendar($httpClient);
    $calendarClient->setRequestorId($userEmail);