1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect2 id="zend.oauth.introduction.getting-started">
<title>Getting Started</title>
<para>
With the OAuth protocol explained, let's show a simple example of it with
source code. Our new Consumer will be handling Twitter Status submissions.
To do so, it will need to be registered with Twitter in order to receive
an OAuth Consumer Key and Consumer Secret. This are utilised to obtain
an Access Token before we use the Twitter <acronym>API</acronym> to post a status message.
</para>
<para>
Assuming we have obtained a key and secret, we can start the OAuth workflow
by setting up a <classname>Zend_Oauth_Consumer</classname> instance as
follows passing it a configuration (either an array or <classname>Zend_Config</classname>
object).
</para>
<programlisting language="php"><![CDATA[
$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);
]]></programlisting>
<para>
The callbackUrl is the URI we want Twitter to request from our server
when sending information. We'll look at this later. The siteUrl is the
base URI of Twitter's OAuth <acronym>API</acronym> endpoints. The full list of endpoints
include http://twitter.com/oauth/request_token, http://twitter.com/oauth/access_token,
and http://twitter.com/oauth/authorize. The base siteUrl utilises a convention
which maps to these three OAuth endpoints (as standard) for requesting a
request token, access token or authorization. If the actual endpoints of
any service differ from the standard set, these three URIs can be separately
set using the methods <methodname>setRequestTokenUrl()</methodname>,
<methodname>setAccessTokenUrl()</methodname>,
and <methodname>setAuthorizeUrl()</methodname> or the configuration fields requestTokenUrl,
accessTokenUrl and authorizeUrl.
</para>
<para>
The consumerKey and consumerSecret are retrieved from Twitter when your
application is registered for OAuth access. These also apply to any OAuth
enabled service, so each one will provide a key and secret for your
application.
</para>
<para>
All of these configuration options may be set using method calls simply
by converting from, e.g. callbackUrl to setCallbackUrl().
</para>
<para>
In addition, you should note several other configuration values not
explicitly used: requestMethod and requestScheme. By default,
<classname>Zend_Oauth_Consumer</classname> sends requests as POST (except for a
redirect which uses <constant>GET</constant>). The customised client (see later) also
includes its authorization by way of a header. Some services may, at their discretion,
require alternatives. You can reset the requestMethod (which defaults
to Zend_Oauth::POST) to Zend_Oauth::GET, for example, and reset the
requestScheme from its default of Zend_Oauth::REQUEST_SCHEME_HEADER to one
of Zend_Oauth::REQUEST_SCHEME_POSTBODY or
Zend_Oauth::REQUEST_SCHEME_QUERYSTRING. Typically the defaults should work
fine apart from some exceptional cases. Please refer to the service provider's
documentation for more details.
</para>
<para>
The second area of customisation is how <acronym>HMAC</acronym> operates
when calculating/comparing them for all requests. This is configured using
the signatureMethod configuration field or <methodname>setSignatureMethod()
</methodname>. By default this is HMAC-SHA1. You can set it also to a provider's
preferred method including RSA-SHA1. For RSA-SHA1, you should also configure
RSA private and public keys via the rsaPrivateKey and rsaPublicKey configuration
fields or the <methodname>setRsaPrivateKey()</methodname> and
<methodname>setRsaPublicKey()</methodname> methods.
</para>
<para>
The first part of the OAuth workflow is obtaining a request token. This
is accomplished using:
</para>
<programlisting language="php"><![CDATA[
$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);
// fetch a request token
$token = $consumer->getRequestToken();
]]></programlisting>
<para>
The new request token (an instance of <classname>Zend_Oauth_Token_Request
</classname>) is unauthorized. In order to exchange it for an authorized
token with which we can access the Twitter <acronym>API</acronym>, we need the user to
authorize it. We accomplish this by redirecting the user to Twitter's authorize endpoint
via:
</para>
<programlisting language="php"><![CDATA[
$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);
// fetch a request token
$token = $consumer->getRequestToken();
// persist the token to storage
$_SESSION['TWITTER_REQUEST_TOKEN'] = serialize($token);
// redirect the user
$consumer->redirect();
]]></programlisting>
<para>
The user will now be redirected to Twitter. They will be asked to authorize
the request token attached to the redirect URI's query string. Assuming they
agree, and complete the authorization, they will be again redirected, this
time to our Callback URL as previously set (note that the callback URL is
also registered with Twitter when we registered our application).
</para>
<para>
Before redirecting the user, we should persist the request token to storage.
For simplicity I'm just using the user's session, but you can easily use a
database for the same purpose, so long as you tie the request token to the
current user so it can be retrieved when they return to our application.
</para>
<para>
The redirect URI from Twitter will contain an authorized Access Token. We
can include code to parse out this access token as follows - this source
code would exist within the executed code of our callback URI. Once parsed
we can discard the previous request token, and instead persist the access
token for future use with the Twitter <acronym>API</acronym>. Again, we're simply persisting
to the user session, but in reality an access token can have a long lifetime
so it should really be stored to a database.
</para>
<programlisting language="php"><![CDATA[
$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);
if (!empty($_GET) && isset($_SESSION['TWITTER_REQUEST_TOKEN'])) {
$token = $consumer->getAccessToken(
$_GET,
unserialize($_SESSION['TWITTER_REQUEST_TOKEN'])
);
$_SESSION['TWITTER_ACCESS_TOKEN'] = serialize($token);
// Now that we have an Access Token, we can discard the Request Token
$_SESSION['TWITTER_REQUEST_TOKEN'] = null;
} else {
// Mistaken request? Some malfeasant trying something?
exit('Invalid callback request. Oops. Sorry.');
}
]]></programlisting>
<para>
Success! We have an authorized access token - so it's time to actually
use the Twitter <acronym>API</acronym>. Since the access token must be included with every
single <acronym>API</acronym> request, <classname>Zend_Oauth_Consumer</classname> offers a
ready-to-go <acronym>HTTP</acronym> client (a subclass of
<classname>Zend_Http_Client</classname>) to use either by itself or by passing it as a
custom <acronym>HTTP</acronym> Client to another library or
component. Here's an example of using it standalone. This can be done
from anywhere in your application, so long as you can access the OAuth
configuration and retrieve the final authorized access token.
</para>
<programlisting language="php"><![CDATA[
$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$statusMessage = 'I\'m posting to Twitter using Zend_Oauth!';
$token = unserialize($_SESSION['TWITTER_ACCESS_TOKEN']);
$client = $token->getHttpClient($configuration);
$client->setUri('http://twitter.com/statuses/update.json');
$client->setMethod(Zend_Http_Client::POST);
$client->setParameterPost('status', $statusMessage);
$response = $client->request();
$data = Zend_Json::decode($response->getBody());
$result = $response->getBody();
if (isset($data->text)) {
$result = 'true';
}
echo $result;
]]></programlisting>
<para>
As a note on the customised client, this can be passed to most
Zend Framework service or other classes using <classname>Zend_Http_Client
</classname> displacing the default client they would otherwise use.
</para>
</sect2>
|