<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:thr="http://purl.org/syndication/thread/1.0"
  xml:lang="en"
   >
  <title type="text">Death of a Gremmie</title>
  <subtitle type="text">Brian Neal's blog about programming.</subtitle>

  <updated>2012-05-13T18:30:33Z</updated>
  <generator uri="http://blogofile.com/">Blogofile</generator>

  <link rel="alternate" type="text/html" href="http://deathofagremmie.com" />
  <id>http://deathofagremmie.com/feed/atom/</id>
  <link rel="self" type="application/atom+xml" href="http://deathofagremmie.com/feed/atom/" />
  <entry>
    <author>
      <name>Brian Neal</name>
      <uri>http://deathofagremmie.com</uri>
    </author>
    <title type="html"><![CDATA[Implementing OAuth using Google's Python Client Library]]></title>
    <link rel="alternate" type="text/html" href="http://deathofagremmie.com/2011/07/04/implementing-oauth-using-google-s-python-client-library" />
    <id>http://deathofagremmie.com/2011/07/04/implementing-oauth-using-google-s-python-client-library</id>
    <updated>2011-07-04T13:00:00Z</updated>
    <published>2011-07-04T13:00:00Z</published>
    <category scheme="http://deathofagremmie.com" term="Python" />
    <category scheme="http://deathofagremmie.com" term="OAuth" />
    <category scheme="http://deathofagremmie.com" term="GData" />
    <category scheme="http://deathofagremmie.com" term="Google" />
    <summary type="html"><![CDATA[Implementing OAuth using Google's Python Client Library]]></summary>
    <content type="html" xml:base="http://deathofagremmie.com/2011/07/04/implementing-oauth-using-google-s-python-client-library"><![CDATA[<div class="document">
<p>My <a class="reference external" href="http://djangoproject.com">Django</a> powered website allows users to submit events for a site calendar
that is built upon Google Calendar.  After an admin approves events, I use
Google's <a class="reference external" href="http://code.google.com/apis/calendar/data/2.0/developers_guide_python.html">Python Client Library</a> to add, delete, or update events on the Google
calendar associated with my personal Google account. I wrote this application a
few years ago, and it used the <a class="reference external" href="http://code.google.com/apis/calendar/data/2.0/developers_guide_python.html#AuthClientLogin">ClientLogin</a> method for authentication. I
recently decided to upgrade this to the <a class="reference external" href="http://code.google.com/apis/gdata/docs/auth/oauth.html">OAuth</a> authentication method. The
ClientLogin method isn't very secure and it doesn't play well with Google's
<a class="reference external" href="http://googleblog.blogspot.com/2011/02/advanced-sign-in-security-for-your.html">two-step verification</a>. After hearing about a friend who had his GMail account
compromised and all his email deleted I decided it was long past due to get
two-step verification on my account. But first I needed to upgrade my web
application to OAuth.</p>
<p>In this post I'll boil down the code I used to implement the elaborate OAuth
dance. It really isn't that much code, but the Google documentation is somewhat
confusing and scattered across a bewildering number of documents. I found at
least one error in the documentation that I will point out. Although I am using
Django, I will omit details specific to Django where I can.</p>
<p>In addition to switching from ClientLogin to OAuth, I also upgraded to version
2.0 of the Google Data API. This had more implications for my calendar-specific
code, and perhaps I can go over that in a future post.</p>
<div class="section" id="getting-started-and-registering-with-google">
<h3>Getting started and registering with Google</h3>
<p>To understand the basics of OAuth, I suggest you read <a class="reference external" href="http://code.google.com/apis/accounts/docs/OAuth.html">OAuth 1.0 for Web
Applications</a>. I decided to go for maximum security and use RSA-SHA1 signing on
all my requests to Google. This requires that I verify my domain and then
<a class="reference external" href="http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto.html">register my application</a> with Google, which includes uploading a security
certificate. Google provides documentation that describes how you can <a class="reference external" href="http://code.google.com/apis/gdata/docs/auth/oauth.html#GeneratingKeyCert">create a
self-signing private key and certificate</a> using OpenSSL.</p>
</div>
<div class="section" id="fetching-a-request-token-and-authorizing-access">
<h3>Fetching a Request Token and authorizing access</h3>
<p>To perform the first part of the OAuth dance, you must ask Google for a request
token. When you make this request, you state the &quot;scope&quot; of your future work by
listing the Google resources you are going to access. In our case, this is the
calendar resources. You also provide a &quot;consumer key&quot; that Google assigned to
you when you registered your application. This allows Google to retrieve the
security certificate you previously uploaded when you registered. This is very
important because this request is going to be signed with your private key.
Fortunately the Python library takes care of all the signing details, you simply
must provide your private key in PEM format. And finally, you provide a
&quot;callback URL&quot; that Google will send your browser to after you (or your users)
have manually authorized this request.</p>
<p>Once you have received the request token from Google, you have to squirrel it
away somewhere, then redirect your (or your user's) browser to a Google
authorization page. Once the user has authorized your application, Google sends
the browser to the callback URL to continue the process. Here I show the
distilled code I used that asks for a request token, then sends the user to the
authorization page.</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">gdata.gauth</span>
<span class="kn">from</span> <span class="nn">gdata.calendar_resource.client</span> <span class="kn">import</span> <span class="n">CalendarResourceClient</span>

<span class="n">USER_AGENT</span> <span class="o">=</span> <span class="s">&#39;mydomain-myapp-v1&#39;</span> <span class="c"># my made up user agent string</span>

<span class="n">client</span> <span class="o">=</span> <span class="n">CalendarResourceClient</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="n">USER_AGENT</span><span class="p">)</span>

<span class="c"># obtain my private key that I saved previously on the filesystem:</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">GOOGLE_OAUTH_PRIVATE_KEY_PATH</span><span class="p">,</span> <span class="s">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">rsa_key</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>

<span class="c"># Ask for a request token:</span>
<span class="c"># scopes - a list of scope strings that the request token is for. See</span>
<span class="c"># http://code.google.com/apis/gdata/faq.html#AuthScopes</span>
<span class="c"># callback_url - URL to send the user after authorizing our app</span>

<span class="n">scopes</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;https://www.google.com/calendar/feeds/&#39;</span><span class="p">]</span>
<span class="n">callback_url</span> <span class="o">=</span> <span class="s">&#39;http://example.com/some/url/to/callback&#39;</span>

<span class="n">request_token</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">GetOAuthToken</span><span class="p">(</span>
        <span class="n">scopes</span><span class="p">,</span>
        <span class="n">callback_url</span><span class="p">,</span>
        <span class="n">settings</span><span class="o">.</span><span class="n">GOOGLE_OAUTH_CONSUMER_KEY</span><span class="p">,</span> <span class="c"># from the registration process</span>
        <span class="n">rsa_private_key</span><span class="o">=</span><span class="n">rsa_key</span><span class="p">)</span>

<span class="c"># Before redirecting, save the request token somewhere; here I place it in</span>
<span class="c"># the session (this line is Django specific):</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="n">REQ_TOKEN_SESSION_KEY</span><span class="p">]</span> <span class="o">=</span> <span class="n">request_token</span>

<span class="c"># Generate the authorization URL.</span>
<span class="c"># Despite the documentation, don&#39;t do this:</span>
<span class="c">#    auth_url = request_token.generate_authorization_url(domain=None)</span>
<span class="c"># Do this instead if you are not using a Google Apps domain:</span>
<span class="n">auth_url</span> <span class="o">=</span> <span class="n">request_token</span><span class="o">.</span><span class="n">generate_authorization_url</span><span class="p">()</span>

<span class="c"># Now redirect the user somehow to the auth_url; here is how you might do</span>
<span class="c"># it in Django:</span>
<span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="n">auth_url</span><span class="p">)</span>
</pre></div>
<p>A couple of notes on the above:</p>
<ul class="simple">
<li>You don't have to use <tt class="docutils literal">CalendarResourceClient</tt>, it just made the most sense
for me since I am doing calendar stuff later on. Any class that inherits from
<tt class="docutils literal">gdata.client.GDClient</tt> will work. You might be able to use that class
directly. Google uses <tt class="docutils literal">gdata.docs.client.DocsClient</tt> in their examples.</li>
<li>I chose to store my private key in a file rather than the database. If you do
so, it's probably a good idea to make the file readable only to the user your
webserver runs your application as.</li>
<li>After getting the request token you must save it somehow. You can save it in
the session, the database, or perhaps a file. Since this is only temporary, I
chose to save it in the session. The code I have here is Django specific.</li>
<li>When generating the authorization URL, don't pass in <tt class="docutils literal">domain=None</tt> if you
aren't using a Google Apps domain like the documentation states. This appears
to be an error in the documentation. Just omit it and let it use the default
value of <tt class="docutils literal">&quot;default&quot;</tt> (see the source code).</li>
<li>After using the request token to generate the authorization URL, redirect the
browser to it.</li>
</ul>
</div>
<div class="section" id="extracting-and-upgrading-to-an-access-token">
<h3>Extracting and upgrading to an Access Token</h3>
<p>The user will then be taken to a Google authorization page. The page will show the
user what parts of their Google account your application is trying to access
using the information you provided in the <tt class="docutils literal">scopes</tt> parameter. If the user
accepts, Google will then redirect the browser to your callback URL where we can
complete the process.</p>
<p>The code running at our callback URL must retrieve the request token that we
saved earlier, and combine that with certain <tt class="docutils literal">GET</tt> parameters Google attached
to our callback URL. This is all done for us by the Python library. We then send
this new token back to Google to upgrade it to an actual access token. If this
succeeds, we can then save this new access token in our database for use in
subsequent Google API operations. The access token is a Python object, so you
can serialize it use the pickle module, or use routines provided by Google
(shown below).</p>
<div class="highlight"><pre><span class="c"># Code running at our callback URL:</span>
<span class="c"># Retrieve the request token we saved earlier in our session</span>
<span class="n">saved_token</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="n">REQ_TOKEN_SESSION_KEY</span><span class="p">]</span>

<span class="c"># Authorize it by combining it with GET parameters received from Google</span>
<span class="n">request_token</span> <span class="o">=</span> <span class="n">gdata</span><span class="o">.</span><span class="n">gauth</span><span class="o">.</span><span class="n">AuthorizeRequestToken</span><span class="p">(</span><span class="n">saved_token</span><span class="p">,</span>
                    <span class="n">request</span><span class="o">.</span><span class="n">build_absolute_uri</span><span class="p">())</span>

<span class="c"># Upgrade it to an access token</span>
<span class="n">client</span> <span class="o">=</span> <span class="n">CalendarResourceClient</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="n">USER_AGENT</span><span class="p">)</span>
<span class="n">access_token</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">GetAccessToken</span><span class="p">(</span><span class="n">request_token</span><span class="p">)</span>

<span class="c"># Now save access_token somewhere, e.g. a database. So first serialize it:</span>
<span class="n">access_token_str</span> <span class="o">=</span>  <span class="n">gdata</span><span class="o">.</span><span class="n">gauth</span><span class="o">.</span><span class="n">TokenToBlob</span><span class="p">(</span><span class="n">access_token</span><span class="p">)</span>

<span class="c"># Save to database (details omitted)</span>
</pre></div>
<p>Some notes on the above code:</p>
<ul class="simple">
<li>Once called back, our code must retrieve the request token we saved in our
session. The code shown is specific to Django.</li>
<li>We then combine this saved request token with certain <tt class="docutils literal">GET</tt> parameters that
Google added to our callback URL. The <tt class="docutils literal">AuthorizeRequestToken</tt> function takes care of
those details for us. The second argument to that function requires the full URL
including <tt class="docutils literal">GET</tt> parameters as a string. Here I populate that argument by
using a Django-specific method of retrieving that information.</li>
<li>Finally, you upgrade your token to an access token by making one last call to
Google. You should now save a serialized version of this access token in your
database for future use.</li>
</ul>
</div>
<div class="section" id="using-your-shiny-new-access-token">
<h3>Using your shiny new Access Token</h3>
<p>Once you have saved your access token, you won't have to do this crazy dance
again until the token either expires, or the user revokes your application's
access to the Google account. To use it in a calendar operation, for example,
you simply retrieve it from your database, deserialize it, and then use it to
create a <tt class="docutils literal">CalendarClient</tt>.</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">gdata.calendar.client</span> <span class="kn">import</span> <span class="n">CalendarClient</span>

<span class="c"># retrieve access token from the database:</span>
<span class="n">access_token_str</span> <span class="o">=</span> <span class="o">...</span>
<span class="n">access_token</span> <span class="o">=</span> <span class="n">gdata</span><span class="o">.</span><span class="n">gauth</span><span class="o">.</span><span class="n">TokenFromBlob</span><span class="p">(</span><span class="n">access_token_str</span><span class="p">)</span>

<span class="n">client</span> <span class="o">=</span> <span class="n">CalendarClient</span><span class="p">(</span><span class="n">source</span><span class="o">=</span><span class="n">USER_AGENT</span><span class="p">,</span> <span class="n">auth_token</span><span class="o">=</span><span class="n">access_token</span><span class="p">)</span>

<span class="c"># now use client to make calendar operations...</span>
</pre></div>
</div>
<div class="section" id="conclusion">
<h3>Conclusion</h3>
<p>The main reason I wrote this blog post is I wanted to show a concrete example of
using RSA-SHA1 and version 2.0 of the Google API together. All of the
information I have presented is in the Google documentation, but it is spread
across several documents and jumbled up with example code for version 1.0 and
HMAC-SHA1.  Do not be afraid to look at the source code for the Python client
library.  Despite Google's strange habit of ignoring <a class="reference external" href="http://www.python.org/dev/peps/pep-0008/">PEP-8</a> and using
LongJavaLikeMethodNames, the code is logical and easy to read. Their library is
built up in layers, and you may have to dip down a few levels to find out what
is going on, but it is fairly straightforward to read if you combine it with
their online documentation.</p>
<p>I hope someone finds this useful. Your feedback is welcome.</p>
</div>
</div>
]]></content>
  </entry>
</feed>

