Consuming Magento REST service using Zend_OAuth_Consumer

ZendConsumer

Ok folks. Until today, trying to cover this area completely, I wrote two articles about Magento oAuth and REST services:

This Magento REST and oAuth functionality and ways on which it could be used are so wide that I think that even in this three articles will not cover everything that I wanna share with you, so stay tuned for next articles about this topic in near future :-)

In official Magento documentation, one plain PHP class is written on how to authenticate with oAuth and how to Consume Magento REST web service.
Here I am going to show how you can do it from inside your Magento controller that is acting as REST client this time. Of course, for simplicity, I am not going to handle errors in examples and I am going to consume REST on same Magento installation, but I think that it will be enough to show the point.
Let’s start.

  1. Configure your local Magento installation following last article steps: How to configure Magento REST and oAuth settings
  2. Create Magento controller class in your test module.
  3. Paste source code inside your controller to look like this:
<?php
/**
 *
 * @author     Darko Goleš <darko.goles@inchoo.net>
 * @package    Inchoo
 * @subpackage RestConnect
 *
 * Url of controller is: http://magento.loc/restconnect/test/[action]
 */
class Inchoo_RestConnect_TestController extends Mage_Core_Controller_Front_Action {
    public function indexAction() {
        //Basic parameters that need to be provided for oAuth authentication
        //on Magento
        $params = array(
            'siteUrl' => 'http://magento.loc/oauth',
            'requestTokenUrl' => 'http://magento.loc/oauth/initiate',
            'accessTokenUrl' => 'http://magento.loc/oauth/token',
            'authorizeUrl' => 'http://magento.loc/admin/oAuth_authorize',//This URL is used only if we authenticate as Admin user type
            'consumerKey' => 'h7n8qjybu78cc3n8cdd5dr7ujtl33uqh',//Consumer key registered in server administration
            'consumerSecret' => '2smfjx37a6e4w23jlcrya6iyv5v32fxr',//Consumer secret registered in server administration
            'callbackUrl' => 'http://magento.loc/restconnect/test/callback',//Url of callback action below
        );
        // Initiate oAuth consumer with above parameters
        $consumer = new Zend_Oauth_Consumer($params);
        // Get request token
        $requestToken = $consumer->getRequestToken();
        // Get session
        $session = Mage::getSingleton('core/session');
        // Save serialized request token object in session for later use
        $session->setRequestToken(serialize($requestToken));
        // Redirect to authorize URL
        $consumer->redirect();
        return;
    }
    public function callbackAction() {
        //oAuth parameters
        $params = array(
            'siteUrl' => 'http://magento.loc/oauth',
            'requestTokenUrl' => 'http://magento.loc/oauth/initiate',
            'accessTokenUrl' => 'http://magento.loc/oauth/token',
            'consumerKey' => 'h7n8qjybu78cc3n8cdd5dr7ujtl33uqh',
            'consumerSecret' => '2smfjx37a6e4w23jlcrya6iyv5v32fxr'
        );
        // Get session
        $session = Mage::getSingleton('core/session');
        // Read and unserialize request token from session
        $requestToken = unserialize($session->getRequestToken());
        // Initiate oAuth consumer
        $consumer = new Zend_Oauth_Consumer($params);
        // Using oAuth parameters and request Token we got, get access token
        $acessToken = $consumer->getAccessToken($_GET, $requestToken);
        // Get HTTP client from access token object
        $restClient = $acessToken->getHttpClient($params);
        // Set REST resource URL
        $restClient->setUri('http://magento.loc/api/rest/products');
        // In Magento it is neccesary to set json or xml headers in order to work
        $restClient->setHeaders('Accept', 'application/json');
        // Get method
        $restClient->setMethod(Zend_Http_Client::GET);
        //Make REST request
        $response = $restClient->request();
        // Here we can see that response body contains json list of products
        Zend_Debug::dump($response);
        return;
    }
}

Now open the indexAction of this controller inside your browser. If everything configured correctly, you should be able to get list of products. At my Magento installation, URL is: http://magento.loc/restconnect/test

oAuthLogin1

oAuthAuthorize

Let’s explain above steps a little bit:

  • First we had to define basic neccesary oAuth parameters for Zend_OAuth_Client.
  • After initiating the client, first we get RequestToken. After request token is retreived, we save it into the session for usage in callback action later.
  • Then we call $client->redirect action and we are redirected to the server user login screen.
  • After successful login, we are redirected to Authorize URL in order user to Authorize application.
  • After authorization, server redirects to our callbackUrl we defined in $params. Here we are getting the RequestToken from session and requesting the AccessToken.
  • After AccessToken is retreived from server, oAuth dance is finished and we are preparing the Http client for making the REST request.
  • We make REST request to server resource URL and retreiving the response

Better way

Uf, let me share something more with you dear visitors:
In the meantime I investigated how to power up Magento oAuth, I developed one Model that can be used ro perform above operations even simpler and cleaner from inside your controller, and I wanna share it with you here.

<?php
/**
 *
 * @author     Darko Goleš <darko.goles@inchoo.net>
 * @package    Inchoo
 * @subpackage RestConnect
 */
class Inchoo_RestConnect_Model_Oauth_Client extends Mage_Core_Model_Abstract
{
    private $_callbackUrl;
    private $_siteUrl;
    private $_consumerKey;
    private $_consumerSecret;
    private $_requestTokenUrl;
    private $_accessTokenUrl;
    private $_consumer;
    private $_authorizeUrl;
    private $_userAuthorizationUrl;
    private $_authorized_token;
    const OAUTH_STATE_NO_TOKEN = 0;
    const OAUTH_STATE_REQUEST_TOKEN = 1;
    const OAUTH_STATE_ACCESS_TOKEN = 2;
    const OAUTH_STATE_ERROR = 3;
    public function init($config)
    {
        $this->setOAuthConfig($config);
        return $this;
    }
    public function setAuthorizedToken($token)
    {
        $this->_authorized_token = $token;
    }
    public function getAuthorizedToken()
    {
        if ($this->_authorized_token) {
            return $this->_authorized_token;
        }
        return false;
    }
    public function reset()
    {
        return $this->resetSessionParams();
    }
    public function authenticate()
    {
        $state = $this->getOAuthState();
        $consumer = $this->_getOAuthConsumer();
        try {
            switch ($state) {
                case self::OAUTH_STATE_NO_TOKEN:
                    $requestToken = $this->getRequestToken();
                    $this->setOAuthState(self::OAUTH_STATE_REQUEST_TOKEN);
                    $consumer->redirect();
                    return self::OAUTH_STATE_REQUEST_TOKEN;
                    break;
                case self::OAUTH_STATE_REQUEST_TOKEN:
                    $accessToken = $this->getAccessToken($this->getRequestToken());
                    $this->setAuthorizedToken($accessToken);
                    $this->setOAuthState(self::OAUTH_STATE_ACCESS_TOKEN);
                    return self::OAUTH_STATE_ACCESS_TOKEN;
                    break;
                case self::OAUTH_STATE_ACCESS_TOKEN:
                    return self::OAUTH_STATE_ACCESS_TOKEN;
                default:
                    $this->resetSessionParams();
                    return self::OAUTH_STATE_NO_TOKEN;
                    return;
                    break;
            }
        } catch (Zend_Oauth_Exception $e) {
            $this->resetSessionParams();
            Mage::logException($e);
        } catch (Exception $e) {
            Mage::logException($e);
        }
        return self::OAUTH_STATE_NO_TOKEN;
    }
    private function resetSessionParams()
    {
        $this->getSession()->unsetData('o_auth_state');
        $this->getSession()->unsetData('request_token');
        $this->getSession()->unsetData('o_auth_config');
        $this->getSession()->unsetData('access_token');
        return $this;
    }
    public function getRequestToken()
    {
        $token = $this->_getRequestTokenFromSession();
        if ($token && $token instanceof Zend_Oauth_Token_Request) {
            return $token;
        }
        $token = $this->_getRequestTokenFromServer();
        if ($token && $token instanceof Zend_Oauth_Token_Request) {
            $this->_saveRequestTokenInSession($token);
            return $token;
        }
        return false;
    }
    public function getAccessToken($requestToken)
    {
        $token = $this->_getAccessTokenFromSession();
        if ($token && $token instanceof Zend_Oauth_Token_Access) {
            return $token;
        }
        $token = $this->_getAcessTokenFromServer($requestToken);
        if ($token && $token instanceof Zend_Oauth_Token_Access) {
            $this->_saveAccessTokenInSesion($token);
            return $token;
        }
    }
    private function _getAcessTokenFromServer($requestToken)
    {
        if ($requestToken && $requestToken instanceof Zend_Oauth_Token_Request) {
            $accToken = $this->_getOAuthConsumer()->getAccessToken(
                $_GET,
                $requestToken
            );
        }
        if ($accToken && $accToken instanceof Zend_Oauth_Token_Access) {
            return $accToken;
        }
        return false;
    }
    private function _saveAccessTokenInSesion($accessToken)
    {
        $this->getSession()->setAccessToken(serialize($accessToken));
    }
    private function _getAccessTokenFromSession()
    {
        $accessToken = unserialize($this->getSession()->getAcessToken());
        if ($accessToken && $accessToken instanceof Zend_Oauth_Token_Access) {
            return $accessToken;
        }
        return false;
    }
    private function _getRequestTokenFromServer()
    {
        $token = $this->_getOAuthConsumer()->getRequestToken();
        return $token;
    }
    private function _saveRequestTokenInSession(Zend_Oauth_Token_Request $requestToken)
    {
        $this->getSession()->setRequestToken(serialize($requestToken));
    }
    private function _getRequestTokenFromSession()
    {
        $requestToken = unserialize($this->getSession()->getRequestToken());
        if ($requestToken && $requestToken instanceof Zend_Oauth_Token_Request) {
            return $requestToken;
        }
        return false;
    }
    public function getSession()
    {
        return Mage::getSingleton('core/session');
    }
    public function getOAuthToken()
    {
        return $this->getRequest()->getParam('oauth_token', false);
    }
    public function getRequest()
    {
        return Mage::app()->getRequest();
    }
    private function _getOAuthConsumer()
    {
        if ($consumer = $this->_consumer) {
            if ($consumer instanceof Zend_Oauth_Consumer) {
                return $this->_consumer;
            }
        }
        $this->_consumer = new Zend_Oauth_Consumer($this->getOAuthConfig());
        return $this->_consumer;
    }
    private function getOAuthConfig()
    {
        $config = array(
            'callbackUrl'     => $this->_callbackUrl,
            'siteUrl'         => $this->_siteUrl,
            'consumerKey'     => $this->_consumerKey,
            'consumerSecret'  => $this->_consumerSecret,
            'requestTokenUrl' => $this->_requestTokenUrl,
            'accessTokenUrl'  => $this->_accessTokenUrl,
        );
        if ($this->_authorizeUrl && $this->_authorizeUrl != '') {
            $config['authorizeUrl'] = $this->_authorizeUrl;
        }
        if ($this->_userAuthorizationUrl && $this->_userAuthorizationUrl != '') {
            $config['userAuthorizationUrl'] = $this->_userAuthorizationUrl;
        }
        return $config;
    }
    private function setOAuthConfig($config)
    {
        $this->getSession()->setOAuthConfig(serialize($config));
        foreach ($config as $key => $val) {
            $_key = '_' . $key;
            $this->$_key = $val;
        }
    }
    public function getConfigFromSession()
    {
        $config = unserialize($this->getSession()->getOAuthConfig());
        if ($config && is_array($config)) {
            return $config;
        }
        return false;
    }
    private function setOAuthState($state)
    {
        $this->getSession()->setOAuthState($state);
    }
    public function getOAuthState()
    {
        $state = $this->getSession()->getOAuthState();
        if ($state == null) {
            return self::OAUTH_STATE_NO_TOKEN;
        }
        $paramOAuthToken = $this->getOAuthToken();
        if ($paramOAuthToken == false && $state == self::OAUTH_STATE_REQUEST_TOKEN) {
            $this->resetSessionParams();
            return self::OAUTH_STATE_NO_TOKEN;
        }
        return $state;
    }
}

Create your own Model file inside your extension dir, and paste above source code there (of course, don’t forget to rename the class to fit your needs).

After that, you just need to have controller like this:

<?php
/**
 *
 * @author     Darko Goleš <darko.goles@inchoo.net>
 * @package    Inchoo
 * @subpackage RestConnect
 *
 * Url of controller is: http://magento.loc/restconnect/test/[action]
 */
class Inchoo_RestConnect_TestController extends Mage_Core_Controller_Front_Action {
    public function indexAction() {
        //Basic parameters that need to be provided for oAuth authentication
        //on Magento
        $params = array(
            'siteUrl' => 'http://magento.loc/oauth',
            'requestTokenUrl' => 'http://magento.loc/oauth/initiate',
            'accessTokenUrl' => 'http://magento.loc/oauth/token',
            'authorizeUrl' => 'http://magento.loc/admin/oAuth_authorize', //This URL is used only if we authenticate as Admin user type
            'consumerKey' => 'h7n8qjybu78cc3n8cdd5dr7ujtl33uqh', //Consumer key registered in server administration
            'consumerSecret' => '2smfjx37a6e4w23jlcrya6iyv5v32fxr', //Consumer secret registered in server administration
            'callbackUrl' => 'http://magento.loc/restconnect/test/callback', //Url of callback action below
        );
        $oAuthClient = Mage::getModel('inchoo_restconnect/oauth_client');
        $oAuthClient->reset();
        $oAuthClient->init($params);
        $oAuthClient->authenticate();
        return;
    }
    public function callbackAction() {
        $oAuthClient = Mage::getModel('inchoo_restconnect/oauth_client');
        $params = $oAuthClient->getConfigFromSession();
        $oAuthClient->init($params);
        $state = $oAuthClient->authenticate();
        if ($state == Inchoo_RestConnect_Model_OAuth_Client::OAUTH_STATE_ACCESS_TOKEN) {
            $acessToken = $oAuthClient->getAuthorizedToken();
        }
        $restClient = $acessToken->getHttpClient($params);
        // Set REST resource URL
        $restClient->setUri('http://magento.loc/api/rest/products');
        // In Magento it is neccesary to set json or xml headers in order to work
        $restClient->setHeaders('Accept', 'application/json');
        // Get method
        $restClient->setMethod(Zend_Http_Client::GET);
        //Make REST request
        $response = $restClient->request();
        // Here we can see that response body contains json list of products
        Zend_Debug::dump($response);
        return;
    }
}

If you use this source, please leave the credit at the top of the file. Thanks.

I hope this article helped to better understand oAuth and REST web services with Magento. :-)

12
Top

Care to rate this post?

Author

Darko Goles

Ex Inchooer

Darko worked at Inchoo as Backend Developer from March 2011 to January 2014

Other posts from this author

Discussion 12 Comments

Add Comment
  1. fabrice

    Hi Darko, I’m stucked at
    2.Create Magento controller class in your test module.
    3. Paste source code inside your controller to look like this:[...]

    Could you explain me which structure I have to create exactly?
    I created this in code/local, my module name is Vac
    /Vac/RestConnect/controllers/Test.php
    /Vac/RestConnect/etc/config.xml (but I don’t know what to put here exactly)
    And my module is declared in etc/modules/Vac_RestConnect.xml
    But I only get a 404 when trying.
    Any help would be much appreciated!
    cheers from Switzerland

  2. @fabrice, you should create standard Magento module with regular configuration. Please try to Google for: create own controller magento and you will find the answer :-)

  3. Thank you for this tutorial,

    Work perfect for me

  4. Federico

    Hi Darko, After successful login I’m being redirected to the customer account panel. As in your example you are redirected to the Authorise URL.
    Do you have any idea if this is to be expected or am i missing something?

    Any help would be appreciated.
    Thanks for the tutorial.

  5. Alexander

    Many thanks for author.

    Only thing that I want to add:

    ~~~ Oauth_Client line 71
    case self::OAUTH_STATE_ACCESS_TOKEN:
    $accessToken = $this->_getAccessTokenFromSession();
    if ($accessToken && $accessToken instanceof Zend_Oauth_Token_Access) {
    $this->setAuthorizedToken($accessToken);
    }
    return self::OAUTH_STATE_ACCESS_TOKEN;
    ~~~
    you shouldn’t authorize each time with this code applied while session dies.

  6. Pablo

    Hi Darko

    thanks for your articles, very well explained. I have a question for you, are Magento REST APIs meant to be consumed within a user module? Let me explain. I am trying to connect with an external desktop app, however I cannot even get the unathorized token. I tracked than this problem to Server.php in Oauth module, and it looks like the following line is not getting the headers when trying to consume the service from an external application:

    $authHeaderValue = $this->_request->getHeader(‘Authorization’);

    I checked the request object and is not supposed to have the getHeader anyway, so that makes me confused. Originally, the request object is set on the constructor of the said class like this:

    if (is_object($request)) {
    if (!$request instanceof Zend_Controller_Request_Http) {
    throw new Exception(‘Invalid request object passed’);
    }
    $this->_request = $request;

    } else {
    $this->_request = Mage::app()->getRequest();

    }

    Thus, I am wondering if I am supposed to create the module to be able to consume the service, or if there is way to do it directly from an external app. Thanks!

  7. Krupal

    Hi,

    How can we create new REST API with new resources. For example if i am creating a new extension and then i have to create API for it using new resources like event module then how i can i create REST API for it. Please guide me.

    Thanks

  8. akhilesh

    how can I update product using REST API?

  9. akhilesh

    Bdw this post is excellent. working very well

  10. Hi I am using all instruction according to written but I run my module it rediect to 404 page with http://103.248.190.173/~sampleco/index.php/admin/oAuth_authorize?oauth_token=c532e26122758bbd07a4c6d61c42617d
    url so please let me what could be error.

  11. every magento I am rediect to 404 when I run according to your custom module When I run
    http://itsindev.com/magento/tailwagsthedog/index.php/hello/index

    then it goes to

    http://itsindev.com/magento/tailwagsthedog/index.php/admin/oAuth_authorize?oauth_token=g0h9vf1l0fl96ikym9e85g9yseopw2nd

    It redirects to this url so please let me know is correct or where could be problem.

  12. Hi Drako,
    I am not expert in Magento. can you help me, where in my magento setup should i do this:
    “Create Magento controller class in your test module.”
    I mean which file or folder of my magento setup e.g.”app/code”,”skin”…

Add Your Comment

Please wrap all source codes with [code][/code] tags.
Top