Skip to content
World Wide Web Server edited this page Jul 4, 2012 · 14 revisions

Category:Libraries::OAuth Category:Library::OAuth

I wrote this library to work with the youtube api. It will let you get an OAuth Request token, authorize the request token, then retrieve an access token. It should be noted that you have to have OAuth setup with google before this will work.

This library uses a helper I wrote in conjunction and have already posted on this wiki. It can be found at [url]http://codeigniter.com/wiki/OAuth_Helper/[/url] it needs to be included if you want to use this library as it does all of the signing. Also read what I posted about it for some helpful tips/sites.

In theory you can use this library to authenticate with all of the different services google offers that use OAuth however I have not tested this the only service that I have tested against is YouTube. That aside though supposedly all you would need to do to authenticate with a different service would be to specify a different 'scope' constant. All of the other constants would remain the same.

For those not familiar with OAuth it is a means of authenticating with another web service without having to store the users username and password for the other service on your site. You can read more about it at [url]http://oauth.net/[/url]

To do this action requires first that a site sends a request to the service in question to retrieve a request token. The site must then redirect to the service and provide the request token to have the user authorize it. Once the user authorizes the request token they are redirected back to your site which is then given authorized oauth token as well as the oauth verifer. These values can then be exchanged for an access token which is what is used to make authenticated requests on the users behalf. This might seem like a lot and to some degree it is but the user only sees a fraction of this, and the whole experience is pretty seamless.

Now I will show you how to use the code first you want to initialize the library and pass in your consumer key and secret. Your key is defined by google after you confirm your OAuth account, it tends to be your base url without the www.

So example.com would be the key for http://www.example.com

Your consumer secret can either be defined by google if you have elected to use HMAC-SHA1 as your signing algorithm. If you chose RSA-SHA1 as your signing algorithm it would be the file path to your .pem file which is the signing certificate you would upload to google. Read the doc I wrote on the helper for links on how to generate these files.

If you decide to use RSA-SHA1 I suggest making your .pem inaccessible using an htaccess file restriction or something. [strong]If someone figures out your secret whether RSA or HMAC your users are compromised so keep it safe and secure.[/strong]

I was unable to get HMAC signatures to work with google so I ended up going with RSA (I later realized I was missing some stuff from my HMAC signature and fixed my helper but by then I was already using RSA.) Much of the library defaults to RSA as the signing algorithm so if you want to make things easier on your self I would use that.

Here is the first call to load the library (I put my key and secret into a config file for easy access and changing): [code]

$params['key'] = $this->config->item('google_consumer_key'); $params['secret'] = $this->config->item('google_consumer_secret'); $this->load->library('google_oauth', $params);

[/code]

You can change the signing algorithm and http method by setting the following in your params array.

[code] $params['method'] = "POST"; $params['algorithm'] = "HMAC-SHA1"; [/code]

If you do not define these parameters they default to GET and RSA-SHA1 respectively.

Next we will start by getting a request token [code] $service_url = $this->google_oauth->get_request_token(site_url("/user/youtube_access")); redirect($service_url); [/code] You need to specify a url to redirect back to after the user has authorized the request token. This method will return a url to the service you wish to authenticate with all you need to do is redirect to the service url.

NOTE: If you are using HMAC signing then the get_request_token method will return an array with keys "token_secret" and "redirect". You will want to temporarily store the token secret value as you will use it in the access step. Then redirect to the "redirect" value.

After this things go out of your hands your user is presented with a page to login to the service in question and then they must click a button to approve access of your site to the service. If they deny access you wont be able to make authenticated requests.

Assuming we are successful the service redirect back to our site to the url we specified. In this case its http://www.example.com/index.php/user/youtube_access but at the end of this url they have tacked on an oauth_token and oauth_verifier. I tried using all kinds of things to get at these but since CI doesn't offer much support for GET I was finally successful with parsing $_SERVER['REQUEST_URI']. Anyway if you are able to get at these variables you can pass them into the access method if not it will attempt to get them itself so its probably best if you just let it do its thing. We need to reload the library since we left our site. [code] $params['key'] = $this->config->item('google_consumer_key'); $params['secret'] = $this->config->item('google_consumer_secret');

$this->load->library('google_oauth', $params); $oauth = $this->google_oauth->get_access_token(); [/code]

NOTE: If you are using HMAC signing you need to specify the token_secret you got from the request step as the second parameter of this method. So [code] $oauth = $this->google_oauth->get_access_token(false, $token_secret); [/code]

The access method will return an array with keys of 'oauth_token', and 'oauth_token_secret' These values are your access token and your access token secret. You should store these in your database.

Now you have an access token and can make google service requests on your users behalf. You should know that users can revoke access at any time rendering your token useless. Also if you decide to use RSA as your signing method you do not need the token secret that is only necessary if you are using HMAC.

Here are both methods from my controller (I use RSA signing): [code] public function youtube_request() { $params['key'] = $this->config->item('google_consumer_key'); $params['secret'] = $this->config->item('google_consumer_secret');

$this->load->library('google_oauth', $params);
redirect($this->google_oauth->get_request_token(site_url("/user/youtube_access")));

}

public function youtube_access() { $params['key'] = $this->config->item('google_consumer_key'); $params['secret'] = $this->config->item('google_consumer_secret');

$this->load->library('google_oauth', $params);
$oauth = $this->google_oauth->get_access_token();

$this->_store_in_db('youtube_token', $oauth['oauth_token']);
$this->_store_in_db('youtube_secret', $oauth['oauth_token_secret']);
    
redirect(site_url());

} [/code]

If you were going to use HMAC signing it would look like this:

[code]

public function youtube_request() { $params['key'] = $this->config->item('google_consumer_key'); $params['secret'] = $this->config->item('google_consumer_secret'); $params['algorithm'] = "HMAC-SHA1";

$this->load->library('google_oauth', $params);
$response = $this->google_oauth->get_request_token(site_url("/user/youtube_access"));

$this->_store_somewhere($response['token_secret']);

redirect($response['redirect']);

}

public function youtube_access() { $params['key'] = $this->config->item('google_consumer_key'); $params['secret'] = $this->config->item('google_consumer_secret'); $params['algorithm'] = "HMAC-SHA1";

$this->load->library('google_oauth', $params);

$token_secret = $this->_get_from_storage('token_secret');

$oauth = $this->google_oauth->get_access_token(false, $token_secret);

$this->_store_in_db('youtube_token', $oauth['oauth_token']);
$this->_store_in_db('youtube_secret', $oauth['oauth_token_secret']);
    
redirect(site_url());

}

[/code]

And here is the full library: If you would rather download the file you can find it at by blog: [url]http://jimdoescode.blogspot.com/2010/09/oauth-and-youtube.html[/url]

[code] <?php if (!defined('BASEPATH')) exit('No direct script access allowed'); /**

  • This library is meant to get you an oauth access token

  • for a google service. You can define which service by

  • changing the SCOPE constant. You will need to pass in

  • your consumer key and secret upon loading this library.

  • I would like to note that the HMAC-SHA1 hashes google

  • generates seem to be different from those that are correctly

  • generated it could be I was signing my requests wrong (I did

  • make some corrections to how that works on the helper) or its

  • possible that google is doing it wrong (I read a number of

  • posts about people seeking help who were told to use RSA).

  • Either way I can say that I have used the RSA-SHA1 signing

  • method with out any issues and I would recommend you use that. */ class google_oauth { const SCHEME = 'https'; const HOST = 'www.google.com'; const AUTHORIZE_URI = '/accounts/OAuthAuthorizeToken'; const REQUEST_URI = '/accounts/OAuthGetRequestToken'; const ACCESS_URI = '/accounts/OAuthGetAccessToken';

    //This should be changed to correspond with the //google service you are authenticating against. const SCOPE = 'https://gdata.youtube.com'; //YouTube

    //Array that should contain the consumer secret and //key which should be passed into the constructor. private $_consumer = false;

    /**

    • Pass in a parameters array which should look as follows:

    • array('key'=>'example.com', 'secret'=>'mysecret');

    • Note that the secret should either be a hash string for

    • HMAC signatures or a file path string for RSA signatures.

    • @param array $params */ public function google_oauth($params) { $this->CI = get_instance(); $this->CI->load->helper('oauth'); //Set defaults for method and algorithm if they are not specified if(!array_key_exists('method', $params))$params['method'] = 'GET'; if(!array_key_exists('algorithm', $params))$params['algorithm'] = OAUTH_ALGORITHMS::RSA_SHA1;

      $this->_consumer = $params; }

    /**

    • This is called to begin the oauth token exchange. This should only
    • need to be called once for a user, provided they allow oauth access.
    • It will return a URL that your site should redirect to, allowing the
    • user to login and accept your application.
    • @param string $callback the page on your site you wish to return to
    •                     after the user grants your application access.
      
    • @return mixed either the URL to redirect to, or if they specified HMAC
    •     signing an array with the token_secret and the redirect url
      

    */ public function get_request_token($callback) { $baseurl = self::SCHEME.'://'.self::HOST.self::REQUEST_URI;

     //Generate an array with the initial oauth values we need
     $auth = build_auth_array($baseurl, $this->_consumer['key'], $this->_consumer['secret'],
                              array('oauth_callback'=>urlencode($callback), 'scope'=>urlencode(self::SCOPE)),
                              $this->_consumer['method'], $this->_consumer['algorithm']);
     //Create the "Authorization" portion of the header
     $str = '';
     foreach($auth AS $key=>$value)
         if($key != 'scope')$str .= ",{$key}=\"{$value}\"";//Do not include scope in the Authorization string.
     $str = substr($str, 1);
     $str = 'Authorization: OAuth '.$str;
     //Send it
     $response = $this->_connect("{$baseurl}?scope={$auth['scope']}", $str);
     //We should get back a request token and secret which
     //we will add to the redirect url.
     parse_str($response, $resarray);
     //Return the full redirect url and let the user decide what to do from there.
     $redirect = self::SCHEME.'://'.self::HOST.self::AUTHORIZE_URI."?oauth_token={$resarray['oauth_token']}";
     //If they are using HMAC then we need to return the token secret for them to store.
     if($this->_consumer['algorithm'] == OAUTH_ALGORITHMS::RSA_SHA1)return $redirect;
     else return array('token_secret'=>$resarray['oauth_token_secret'], 'redirect'=>$redirect);
    

    }

    /**

    • This is called to finish the oauth token exchange. This too should

    • only need to be called once for a user. The token returned should

    • be stored in your database for that particular user.

    • @param string $token this is the oauth_token returned with your callback url

    • @param string $secret this is the token secret supplied from the request (Only required if using HMAC)

    • @param string $verifier this is the oauth_verifier returned with your callback url

    • @return array access token and token secret */ public function get_access_token($token = false, $secret = false, $verifier = false) { //If no request token was specified then attempt to get one from the url if($token === false && isset($_GET['oauth_token']))$token = $_GET['oauth_token']; if($verifier === false && isset($_GET['oauth_verifier']))$verifier = $_GET['oauth_verifier']; //If all else fails attempt to get it from the request uri. if($token === false && $verifier === false) { $uri = $_SERVER['REQUEST_URI']; $uriparts = explode('?', $uri);

       $authfields = array();
       parse_str($uriparts[1], $authfields);
       $token = $authfields['oauth_token'];
       $verifier = $authfields['oauth_verifier'];
      

      }

      $tokenddata = array('oauth_token'=>urlencode($token), 'oauth_verifier'=>urlencode($verifier)); if($secret !== false)$tokenddata['oauth_token_secret'] = urlencode($secret);

      $baseurl = self::SCHEME.'://'.self::HOST.self::ACCESS_URI; //Include the token and verifier into the header request. $auth = get_auth_header($baseurl, $this->_consumer['key'], $this->_consumer['secret'], $tokenddata, $this->_consumer['method'], $this->_consumer['algorithm']); $response = $this->_connect($baseurl, $auth); //Parse the response into an array it should contain //both the access token and the secret key. (You only //need the secret key if you use HMAC-SHA1 signatures.) parse_str($response, $oauth); //Return the token and secret for storage return $oauth; }

    /**

    • Connects to the server and sends the request,

    • then returns the response from the server.

    • @param $url

    • @param $auth

    • @return */ private function _connect($url, $auth) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ; curl_setopt($ch, CURLOPT_SSLVERSION,3); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array($auth));

      $response = curl_exec($ch); curl_close($ch); return $response; } } // ./system/application/libraries ?> [/code]

Let me know if you have any questions in the comments. I will be releasing a YouTube api once I get the code cleaned up a bit that will incorporate the OAuth access token you retrieve. So keep an eye out for that.

-UPDATE: Changed the library a bit to better handle HMAC signing. I did not test it for google though. I'm using similar techniques for a twitter oauth library and things seem to be working fine. Also linked to my blog where the most up-to-date version of the library can be found incase I let this wiki page fall into disrepair.

Clone this wiki locally