Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: e450766fc8
Fetching contributors…

Cannot retrieve contributors at this time

245 lines (192 sloc) 13.462 kb
<!DOCTYPE html>
<html lang="en">
<title>The sorry state of Python OAuth providers</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="./theme/css/main.css" type="text/css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="pydanny Atom Feed" />
<!--[if IE]>
<script src=""></script><![endif]-->
<!--[if lte IE 7]>
<link rel="stylesheet" type="text/css" media="all" href="./css/ie.css"/>
<script src="./js/IE8.js" type="text/javascript"></script><![endif]-->
<!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" media="all" href="./css/ie6.css"/><![endif]-->
<body id="index" class="home">
<a href="">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="" alt="Fork me on GitHub" />
<header id="banner" class="body">
<h1><a href=".">pydanny </a></h1>
<li><a href="./pages/about.html">About</a></li>
<li><a href="./pages/tools.html">Tools</a></li>
<li><a href="./pages/upcoming.html">Upcoming</a></li>
<li ><a href="./category/audrey.html">Audrey</a></li>
<li ><a href="./category/blog.html">Blog</a></li>
<li ><a href="./category/django.html">Django</a></li>
<li class="active"><a href="./category/python.html">Python</a></li>
</header><!-- /#banner -->
<section id="content" class="body">
<h1 class="entry-title">
<a href="the-sorry-state-of-python-oauth-providers.html" rel="bookmark"
title="Permalink to The sorry state of Python OAuth providers">The sorry state of Python OAuth providers</a></h1>
<a href="" class="twitter-share-button" data-count="horizontal" data-via="pydanny">Tweet</a><script type="text/javascript" src=""></script>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2012-03-05T07:30:00">
Mon 05 March 2012
<address class="vcard author">
By <a class="url fn" href="./author/Daniel-Greenfeld.html">Daniel-Greenfeld</a>
<p>In <a href="./category/python.html">python</a>. </p>
<p>tags: <a href="./tag/python.html">python</a><a href="./tag/django.html">django</a><a href="./tag/OAuth.html">OAuth</a><a href="./tag/api.html">api</a><a href="./tag/Consumer-Notebook.html">Consumer-Notebook</a></p>
</footer><!-- /.post-info -->
<p>This is one of those challenging posts to write. The people whose projects I'm going to describe have put in a lot of dedicated, hard work to overcome a challenging subject. Writing an OAuth consumer is a hard problem and writing an OAuth provider is an even harder problem. The efforts put in by the authors of these projects has been nothing short of incredible. The problem, however, is that the existing projects are not usable as-is, and need the support of the community in order to improve.</p>
<p>The terrible thing is that this is a solved problem within our community. Python based projects are successfully implementing OAuth providers, and often using internally hacked versions of the efforts I'm about to describe. However, they aren't giving this back to the community. It might be that they want to protect their competitive edge, but I'm going to be nice and say that it's because their too busy to find time to send pull requests back.</p>
<p>In any case, let me present our use case. For <a class="reference external" href="">Consumer Notebook</a> we want an <a class="reference external" href="">API</a>. We want to be able to track usernames, passwords, and the application using our <a class="reference external" href="">API</a> - which is the OAuth use case. Much as BasicAuth or DigestAuth is the easier way to go in terms of implementation, OAuth was designed for our use case: allowing third-party developers to build apps using our API without having to store credentials. In fact, it's a critical security issue: Twitter dealt with malicious &quot;Twitter apps&quot; stealing usernames and passwords before they switched to OAuth. As an API provider, being an OAuth provider might be more challenging, but it's the responsible thing to do.</p>
<div class="section" id="existing-oauth-providers">
<h2>Existing OAuth Providers</h2>
<p>Time to get into the meat of the issue. Let's look at the current implementations of OAuth providing within the Python community. Again, I wish I didn't have to be negative, but I'm up against the wall:</p>
<div class="section" id="oauth2app-django">
<h3>OAuth2app (Django)</h3>
<p><a class="reference external" href=""></a></p>
<p>OAuth version: 2.0</p>
<ul class="simple">
<li>Strange URL construction that might be a security hole.</li>
<li>Bitwise operators in the logic making it harder to debug. Security is hard. Don't complicate your security code because your mistakes will cost.</li>
<li>Uncommented code. Security is hard. Comment your code.</li>
<li>Documentation outdated and insufficient.</li>
<li>Doesn't work without serious hacking and adding of undocumented parameters. Which means I have to worry if I'm breaking anything.</li>
<li>We managed to get it working with GET requests. Then we realized that we were using GET requests, which seems like a bad idea.</li>
<div class="section" id="django-piston-django">
<h3>django-piston (Django)</h3>
<p><a class="reference external" href=""></a></p>
<p>OAuth version: 1.0</p>
<ul class="simple">
<li>Stalled project.</li>
<li>Documentation insufficient.</li>
<div class="section" id="django-oauth-plus-django">
<h3>django-oauth-plus (Django)</h3>
<p><a class="reference external" href=""></a></p>
<p>OAuth version: 1.0a</p>
<ul class="simple">
<li>Tutorial doesn't work.</li>
<li>Documentation insufficient.</li>
<li>Doesn't work without serious hacking. Which means I have to worry if I'm breaking anything.</li>
<li>We could not get it to work.</li>
<div class="section" id="lastuser-flask">
<h3>lastuser (Flask)</h3>
<p><a class="reference external" href=""></a></p>
<p>OAuth version: 2.0</p>
<ul class="simple">
<li>No documentation</li>
<li>No tests to serve as documentation</li>
<li>Lack of documentation means I'm not sure if it is actually a OAuth provider.</li>
<div class="section" id="python-oauth2-python">
<h3>python-oauth2 (Python)</h3>
<p><a class="reference external" href=""></a> (best example)</p>
<p>OAuth version: 1.0</p>
<ul class="simple">
<li>Called 'OAuth2' but only works with OAuth 1? Really? <strong>WTF?</strong> This needs to fixed.</li>
<li>Documentation insufficient.</li>
<li>Provides only a skeleton of a provider. Not a turnkey solution.</li>
<li>Doesn't work as a provider without serious hacking. Which means I have to worry if I'm breaking anything.</li>
<li>Many, many forks of the project, with various blog posts advising people to use various particular forks rather than the main one.</li>
<div class="section" id="how-about-a-solution">
<h2>How about a solution?</h2>
<p>Alright, I've ranted and laid out out a bunch of bullets identifying a problem. Time to try and fix the problem.</p>
<p>For starters, a production-usable OAuth provider should meet certain standards:</p>
<ul class="simple">
<li>Near turnkey solution</li>
<li>Working code (duplicates above bullet but I'm making a point)</li>
<li>Working tutorials</li>
<li>Commented code</li>
<li>Linted code</li>
<li>Test coverage &gt; 80%</li>
<p>This is my specification. If your project for any Python framework matches it, I'll list it on a forthcoming website that also covers Python based OAuth consumers.</p>
<p>For what it's worth, Idan Gazit has been working on something to help address the problem, specifically <a class="reference external" href=""></a>. It also is intended to cover the Python OAuth consumption issue I didn't cover in this article. It and related efforts need a lot of work, so...</p>
<p>The PyCon US 2012 sprints start on March 12. I think as a community, we Pythonistas should band together and make things right. I think we'll have the brainpower and enough eyes on the problem to make serious headway on the issue, either by fixing existing solutions or creating new ones. Right now I've got interest from people to join in and help, including Idan Gazit, Audrey Roy, George Hickman, and others.</p>
<p>We're willing to put in the time to make OAuth in Python better, how about you?</p>
<p>Join us at the PyCon US sprints either in person or on-line. <a class="reference external" href="">Details of the sprint are near the bottom of this PyCon Sprint page</a>.</p>
<a class="reference external image-reference" href=""><img alt="" class="align-center" id="oauth-logo" src="" /></a>
<hr class="docutils" />
<div class="section" id="updates">
<p>03/05/2012 - Removed Velruse from the list of providers as it's lead, Michael Merickel, clarified that it is not a provider.
03/06/2012 - Added a link to the PyCon OAuth sprints.</p>
<hr class="docutils" />
<p><a class="reference external" href="">Discuss this post on Hacker News</a></p>
</div><!-- /.entry-content -->
<div class="comments">
<h2>Comments !</h2>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_identifier = "the-sorry-state-of-python-oauth-providers.html";
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
<section id="extras" class="body">
<div class="social">
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<li><a href="">twitter</a></li>
<li><a href="">github</a></li>
<li><a href="">facebook</a></li>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="">Pelican</a>, which takes great advantage of <a href="">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "' type='text/javascript'%3E%3C/script%3E"));
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-18066389-3");
} catch(err) {}</script>
<script type="text/javascript">
var disqus_shortname = 'pydanny';
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'http://' + disqus_shortname + '';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
Jump to Line
Something went wrong with that request. Please try again.