Skip to content

Commit 156056b

Browse files
committed
Added docs
1 parent 259dc61 commit 156056b

File tree

7 files changed

+347
-34
lines changed

7 files changed

+347
-34
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.DS_Store
22
*.pyc
33
*.pyo
4+
docs/_build

docs/_static/flask-oauth.png

16.9 KB
Loading

docs/conf.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# If extensions (or modules to document with autodoc) are in another directory,
1717
# add these directories to sys.path here. If the directory is relative to the
1818
# documentation root, use os.path.abspath to make it absolute, like shown here.
19+
sys.path.append(os.path.abspath('..'))
1920
sys.path.append(os.path.abspath('_themes'))
2021

2122
# -- General configuration -----------------------------------------------------
@@ -96,14 +97,17 @@
9697
# Theme options are theme-specific and customize the look and feel of a theme
9798
# further. For a list of options available for each theme, see the
9899
# documentation.
99-
#html_theme_options = {}
100+
html_theme_options = {
101+
'index_logo': 'flask-oauth.png',
102+
'github_fork': 'mitsuhiko/flask-oauth'
103+
}
100104

101105
# Add any paths that contain custom themes here, relative to this directory.
102106
html_theme_path = ['_themes']
103107

104108
# The name for this set of Sphinx documents. If None, it defaults to
105109
# "<project> v<release> documentation".
106-
#html_title = None
110+
html_title = 'Flask-OAuth'
107111

108112
# A shorter title for the navigation bar. Default is the same as html_title.
109113
#html_short_title = None
@@ -211,4 +215,4 @@
211215

212216

213217
# Example configuration for intersphinx: refer to the Python standard library.
214-
intersphinx_mapping = {'http://docs.python.org/': None}
218+
intersphinx_mapping = {'http://docs.python.org/': None}

docs/index.rst

Lines changed: 212 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,218 @@
1-
.. Flask-OAuth documentation master file, created by
2-
sphinx-quickstart on Sat May 8 13:26:52 2010.
3-
You can adapt this file completely to your liking, but it should at least
4-
contain the root `toctree` directive.
1+
Flask-OAuth
2+
===========
53

6-
Welcome to Flask-OAuth's documentation!
7-
=======================================
4+
.. module:: flaskext.oauth
85

9-
Contents:
6+
Flask-OAuth is an extension to `Flask`_ that allows you to interact with
7+
remove `OAuth`_ enabled applications. Currently it only implements the
8+
consumer interface so you cannot expose your own API with OAuth. It
9+
depends on the `python-oauth2`_ module. You can install the requirements
10+
from PyPI with `easy_install` or `pip` or download them by hand.
1011

11-
.. toctree::
12-
:maxdepth: 2
12+
Features
13+
--------
1314

14-
Indices and tables
15-
==================
15+
- support for OAuth 1.0a
16+
- friendly API
17+
- direct integration with Flask
18+
- basic support for remote method invocation of RESTful APIs
1619

17-
* :ref:`genindex`
18-
* :ref:`modindex`
19-
* :ref:`search`
20+
Installation
21+
------------
2022

23+
Install the extension with one of the following commands::
24+
25+
$ easy_install Flask-OAuth
26+
27+
or alternatively if you have `pip` installed::
28+
29+
$ pip install Flask-OAuth
30+
31+
.. _Flask: http://flask.pocoo.org/
32+
.. _OAuth: http://oauth.net/
33+
.. _python-oauth2: http://pypi.python.org/pypi/Flask-OAuth2
34+
35+
Defining Remote Applications
36+
----------------------------
37+
38+
To use connect to a remote application you need to create a :class:`OAuth`
39+
object and register a remote application on it. This can be done with
40+
the :meth:`~OAuth.remote_app` method::
41+
42+
oauth = OAuth()
43+
the_remote_app = oauth.register_app('the remote app',
44+
...
45+
)
46+
47+
A remote application has to defined with a couple of URLs required for the
48+
OAuth machinery: the `request_token_url`, `access_token_url`, and
49+
`authorize_url`. You will most likely get these values after you
50+
registered your own application on the developer page of the remote
51+
application you want to connect with. Additionally a per-application
52+
issued `consumer_key` and `consumer_secret` is needed.
53+
54+
Additionally you can provide a `base_url` that is prefixed to *all*
55+
relative URLs used in the remote app. This would also affect the
56+
`request_token_url` but because The prefix for `oauth` and the regular
57+
twitter API are different one has to provide absolute URLs for the OAuth
58+
token and authenticate methods.
59+
60+
For Twitter the setup would look like this::
61+
62+
twitter = oauth.remote_app('twitter',
63+
base_url='http://api.twitter.com/1/',
64+
request_token_url='http://api.twitter.com/oauth/request_token',
65+
access_token_url='http://api.twitter.com/oauth/access_token',
66+
authorize_url='http://api.twitter.com/oauth/authenticate',
67+
consumer_key='<your key here>',
68+
consumer_secret='<your secret here>'
69+
)
70+
71+
Twitter supports two authorization urls: ``/authenticate`` and
72+
``/authorize``. The difference is the user interface shown to the user on
73+
twitter. ``/authenticate`` should be used if the intent of OAuth is to
74+
use the twitter identity of the user to sign in to your own website, the
75+
``/authorize`` endpoint should be used to just access the twitter API and
76+
not using the user profile on your own website.
77+
78+
Now that the application is created one can start using the OAuth system.
79+
One thing is missing: the tokengetter. OAuth uses a token and a secret to
80+
basically figure out who is connecting to the remote application. After
81+
authentication/authorization this information is passed to a function on
82+
your side and it's your responsibility to remember it.
83+
84+
The following rules apply:
85+
86+
- it's your responsibility to store that information somewhere
87+
- that information lives for as long as the user did not revoke the
88+
access for your application on the remote application. If it was
89+
revoked and the user re-enabled the application you will get different
90+
keys, so if you store them in the database don't forget to check if
91+
they changed in the authorization callback.
92+
- During the authorization handshake a temporary token and secret are
93+
issued, your tokengetter is not used during that period.
94+
95+
For a simple test application, storing that information in the session is
96+
probably good enough::
97+
98+
from flask import session
99+
100+
@twitter.tokengetter
101+
def get_twitter_token():
102+
return session.get('twitter_token')
103+
104+
Note that the function must return `None` if the token does not exist, and
105+
otherwise return a tuple in the form ``(token, secret)``.
106+
107+
Signing in / Authorizing
108+
------------------------
109+
110+
If you want to sign in with Twitter or link a user account with a remote
111+
twitter user, all you have to do is to call into
112+
:meth:`~OAuthRemoteApp.authorize` and pass it the URL to where the user
113+
should be redirected back. Here an example::
114+
115+
@app.route('/login')
116+
def login():
117+
return twitter.authorize(callback=url_for('oauth_authorized',
118+
next=request.args.get('next') or request.referrer or None))
119+
120+
If the application redirects back, Twitter will have passed all the relevant
121+
information to the `oauth_authorized` function. It is passed a special
122+
response object with all the data, or ``None`` if the user denied the
123+
request. This function has to be decorated as
124+
:meth:`~OAuthRemoteApp.authorized_handler`::
125+
126+
from flask import redirect
127+
128+
@app.route('/oauth-authorized')
129+
@twitter.authorized_handler
130+
def oauth_authorized(resp):
131+
next_url = request.args.get('next') or url_for('index')
132+
if resp is None:
133+
flash(u'You denied the request to sign in.')
134+
return redirect(next_url)
135+
136+
session['twitter_token'] = (
137+
resp['oauth_token'],
138+
resp['oauth_token_secret']
139+
)
140+
session['twitter_user'] = resp['screen_name']
141+
142+
flash('You were signed in as %s' % resp['screen_name'])
143+
return redirect(next_url)
144+
145+
As you can see here: we store the token and the associated secret in the
146+
session so that the tokengetter can return it. Additionally we also
147+
remember the Twitter screen name that was sent back to us so that we can
148+
display that information to the user. In larger applications it is
149+
recommended to store that information in the database instead because it
150+
allows you to easier debug things and you can store additional information
151+
associated with the user.
152+
153+
Invoking Remote Methods
154+
-----------------------
155+
156+
Now the user is signed in, that is nice, but most likely you want to use
157+
OAuth to call protected remote API methods and not just sign in. For
158+
that, the remote application object provides a
159+
:meth:`~OAuthRemoteApp.request` method that can request information from
160+
an OAuth protected resource. Additionally there are shortcuts like
161+
:meth:`~OAuthRemoteApp.get` or :meth:`~OAuthRemoteApp.post` to request
162+
data with a certain HTTP method.
163+
164+
For example to create a new tweet you would call into the twitter
165+
application like this::
166+
167+
resp = twitter.post('statuses/update.json', data={
168+
'status': 'The text we want to tweet'
169+
})
170+
if resp.status == 403:
171+
flash('Your tweet was too long.')
172+
else:
173+
flash('Successfully tweeted your tweet (ID: #%s)' % resp.data['id'])
174+
175+
Or to display the users's home timeline we can do something like this::
176+
177+
resp = twitter.get('statuses/home_timeline.json')
178+
if resp.status == 200:
179+
tweets = resp.data
180+
else:
181+
tweets = None
182+
flash('Unable to load tweets from Twitter. Maybe out of '
183+
'API calls or Twitter is overloaded.')
184+
185+
Flask-OAuth will do its best to sent data encoded in the right format to
186+
the server and to decode it when it comes back. Incoming data is encoded
187+
based on the `mimetype` the server sent and stored in the
188+
:attr:`~OAuthResponse.data` attribute. For outgoing data a default of
189+
``'urlencode'`` is assumed and when a different format is wanted, one can
190+
specify it with the `format` parameter. The following formats are
191+
supported:
192+
193+
**Outgoing**:
194+
``'urlencode'`` - form encoded data (`GET` as URL and `POST`/`PUT` as
195+
request body)
196+
``'json'`` - JSON encoded data (`POST`/`PUT` as request body)
197+
198+
**Incoming**
199+
``'urlencode'`` - stored as flat unicode dictionary
200+
``'json'`` - decoded with JSON rules, most likely a dictionary
201+
``'xml'`` - stored as elementtree element
202+
203+
Unkown incoming data is stored as string. If outgoing data of a different
204+
format should be used, a `content_type` can be specified instead and the
205+
data provided a encoded string.
206+
207+
208+
API Reference
209+
-------------
210+
211+
.. autoclass:: OAuth
212+
:members:
213+
214+
.. autoclass:: OAuthRemoteApp
215+
:members:
216+
217+
.. autoclass:: OAuthResponse
218+
:members:

example/tweet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def login():
130130

131131
@app.route('/logout')
132132
def logout():
133-
session.pop('user_id')
133+
session.pop('user_id', None)
134134
flash('You were signed out')
135135
return redirect(request.referrer or url_for('index'))
136136

0 commit comments

Comments
 (0)