[Python-modules-commits] [python-social-auth] 04/05: add documentation files from upstream git

Wolfgang Borgert debacle at moszumanska.debian.org
Sat Dec 24 15:12:32 UTC 2016


This is an automated email from the git hooks/post-receive script.

debacle pushed a commit to branch master
in repository python-social-auth.

commit 78363c7d36575a497f65817d39bd238ddd199c84
Author: W. Martin Borgert <debacle at debian.org>
Date:   Sat Dec 24 15:11:07 2016 +0000

    add documentation files from upstream git
---
 debian/patches/add-docs.patch | 7449 +++++++++++++++++++++++++++++++++++++++++
 debian/patches/series         |    1 +
 2 files changed, 7450 insertions(+)

diff --git a/debian/patches/add-docs.patch b/debian/patches/add-docs.patch
new file mode 100644
index 0000000..8ce37a6
--- /dev/null
+++ b/debian/patches/add-docs.patch
@@ -0,0 +1,7449 @@
+Description: add last published documentation
+Author: W. Martin Borgert <debacle at debian.org>
+Origin: vendor
+Last-Update: 2016-12-24
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- /dev/null
++++ b/docs/Makefile
+@@ -0,0 +1,130 @@
++# Makefile for Sphinx documentation
++#
++
++# You can set these variables from the command line.
++SPHINXOPTS    =
++SPHINXBUILD   = sphinx-build
++PAPER         =
++BUILDDIR      = _build
++
++# Internal variables.
++PAPEROPT_a4     = -D latex_paper_size=a4
++PAPEROPT_letter = -D latex_paper_size=letter
++ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
++
++.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
++
++help:
++	@echo "Please use \`make <target>' where <target> is one of"
++	@echo "  html       to make standalone HTML files"
++	@echo "  dirhtml    to make HTML files named index.html in directories"
++	@echo "  singlehtml to make a single large HTML file"
++	@echo "  pickle     to make pickle files"
++	@echo "  json       to make JSON files"
++	@echo "  htmlhelp   to make HTML files and a HTML help project"
++	@echo "  qthelp     to make HTML files and a qthelp project"
++	@echo "  devhelp    to make HTML files and a Devhelp project"
++	@echo "  epub       to make an epub"
++	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
++	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
++	@echo "  text       to make text files"
++	@echo "  man        to make manual pages"
++	@echo "  changes    to make an overview of all changed/added/deprecated items"
++	@echo "  linkcheck  to check all external links for integrity"
++	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
++
++clean:
++	-rm -rf $(BUILDDIR)/*
++
++html:
++	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
++	@echo
++	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
++
++dirhtml:
++	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
++	@echo
++	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
++
++singlehtml:
++	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
++	@echo
++	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
++
++pickle:
++	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
++	@echo
++	@echo "Build finished; now you can process the pickle files."
++
++json:
++	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
++	@echo
++	@echo "Build finished; now you can process the JSON files."
++
++htmlhelp:
++	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
++	@echo
++	@echo "Build finished; now you can run HTML Help Workshop with the" \
++	      ".hhp project file in $(BUILDDIR)/htmlhelp."
++
++qthelp:
++	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
++	@echo
++	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
++	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
++	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DjangoSocialAuth.qhcp"
++	@echo "To view the help file:"
++	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DjangoSocialAuth.qhc"
++
++devhelp:
++	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
++	@echo
++	@echo "Build finished."
++	@echo "To view the help file:"
++	@echo "# mkdir -p $$HOME/.local/share/devhelp/DjangoSocialAuth"
++	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DjangoSocialAuth"
++	@echo "# devhelp"
++
++epub:
++	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
++	@echo
++	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
++
++latex:
++	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
++	@echo
++	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
++	@echo "Run \`make' in that directory to run these through (pdf)latex" \
++	      "(use \`make latexpdf' here to do that automatically)."
++
++latexpdf:
++	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
++	@echo "Running LaTeX files through pdflatex..."
++	make -C $(BUILDDIR)/latex all-pdf
++	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
++
++text:
++	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
++	@echo
++	@echo "Build finished. The text files are in $(BUILDDIR)/text."
++
++man:
++	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
++	@echo
++	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
++
++changes:
++	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
++	@echo
++	@echo "The overview file is in $(BUILDDIR)/changes."
++
++linkcheck:
++	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
++	@echo
++	@echo "Link check complete; look for any errors in the above output " \
++	      "or in $(BUILDDIR)/linkcheck/output.txt."
++
++doctest:
++	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
++	@echo "Testing of doctests in the sources finished, look at the " \
++	      "results in $(BUILDDIR)/doctest/output.txt."
+--- /dev/null
++++ b/docs/backends/amazon.rst
+@@ -0,0 +1,29 @@
++Amazon
++======
++
++Amazon implemented OAuth2 protocol for their authentication mechanism. To
++enable ``python-social-auth`` support follow this steps:
++
++1. Go to `Amazon App Console`_ and create an application.
++
++2. Fill App Id and Secret in your project settings::
++
++    SOCIAL_AUTH_AMAZON_KEY = '...'
++    SOCIAL_AUTH_AMAZON_SECRET = '...'
++
++3. Enable the backend::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.amazon.AmazonOAuth2',
++        ...
++    )
++
++Further documentation at `Website Developer Guide`_ and `Getting Started for Web`_.
++
++**Note:** This backend supports TLSv1 protocol since SSL will be deprecated
++          from May 25, 2015
++
++.. _Amazon App Console: http://login.amazon.com/manageApps
++.. _Website Developer Guide: https://images-na.ssl-images-amazon.com/images/G/01/lwa/dev/docs/website-developer-guide._TTH_.pdf
++.. _Getting Started for Web: http://login.amazon.com/website
+--- /dev/null
++++ b/docs/backends/angel.rst
+@@ -0,0 +1,21 @@
++Angel List
++==========
++
++Angel uses OAuth v2 for Authentication.
++
++- Register a new application at the `Angel List API`_, and
++
++- fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_ANGEL_KEY = ''
++      SOCIAL_AUTH_ANGEL_SECRET = ''
++
++- extra scopes can be defined by using::
++
++    SOCIAL_AUTH_ANGEL_AUTH_EXTRA_ARGUMENTS = {'scope': 'email messages'}
++
++**Note:**
++Angel List does not currently support returning ``state`` parameter used to
++validate the auth process.
++
++.. _Angel List API: https://angel.co/api/oauth/faq
+--- /dev/null
++++ b/docs/backends/aol.rst
+@@ -0,0 +1,11 @@
++AOL
++===
++
++AOL OpenId doesn't require major settings beside being defined on
++``AUTHENTICATION_BACKENDS```::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.aol.AOLOpenId',
++        ...
++    )
+--- /dev/null
++++ b/docs/backends/appsfuel.rst
+@@ -0,0 +1,46 @@
++Appsfuel
++========
++
++Appsfuel uses OAuth v2 for Authentication check the `official docs`_ too.
++
++- Sign up at the `Appsfuel Developer Program`_
++
++- Create and verify a new app
++
++- On the dashboard click on **Show API keys**
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_APPSFUEL_KEY = '<App UID>'
++      SOCIAL_AUTH_APPSFUEL_SECRET = '<App secret>'
++
++Appsfuel gives you the chance to integrate with **Live** or **Sandbox** env.
++
++
++Appsfuel Live
++-------------
++
++- Add 'social.backends.contrib.appsfuel.AppsfuelBackend' into your
++  ``AUTHENTICATION_BACKENDS``.
++
++- Then you can start using ``{% url social:begin 'appsfuel' %}`` in your
++  templates
++
++
++Appsfuel Sandbox
++----------------
++
++- Add ``'social.backends.appsfuel.AppsfuelOAuth2Sandbox'`` into your
++  ``AUTHENTICATION_BACKENDS``.
++
++- Then you can start using ``{% url social:begin 'appsfuel-sandbox' %}`` in
++  your templates
++
++- Define the settings::
++
++    SOCIAL_AUTH_APPSFUEL_SANDBOX_KEY = '<App UID>'
++    SOCIAL_AUTH_APPSFUEL_SANDBOX_SECRET = '<App secret>'
++
++
++.. _official docs: http://docs.appsfuel.com/api_reference#api_integration
++.. _Appsfuel Developer Program: https://developer.appsfuel.com
+--- /dev/null
++++ b/docs/backends/arcgis.rst
+@@ -0,0 +1,25 @@
++ArcGIS
++======
++
++ArcGIS uses OAuth2 for authentication.
++
++- Register a new application at `ArcGIS Developer Center`_.
++
++
++OAuth2
++------
++
++1. Add the OAuth2 backend to your settings page::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.arcgis.ArcGISOAuth2',
++        ...
++    )
++
++2. Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++    SOCIAL_AUTH_ARCGIS_KEY = ''
++    SOCIAL_AUTH_ARCGIS_SECRET = ''
++
++.. _ArcGIS Developer Center: https://developers.arcgis.com/
+--- /dev/null
++++ b/docs/backends/azuread.rst
+@@ -0,0 +1,20 @@
++Microsoft Azure Active Directory
++================================
++
++To enable OAuth2 support:
++
++- Fill in ``Client ID`` and ``Client Secret`` settings. These values can be
++  obtained easily as described in `Azure AD Application Registration`_ doc::
++
++      SOCIAL_AUTH_AZUREAD_OAUTH2_KEY = ''
++      SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_AZUREAD_OAUTH2_RESOURCE = ''
++
++  This is the resource you would like to access after authentication succeeds.
++  Some of the possible values are: ``https://graph.windows.net`` or
++  ``https://<your Sharepoint site name>-my.sharepoint.com``.
++
++.. _Azure AD Application Registration: https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx
+--- /dev/null
++++ b/docs/backends/battlenet.rst
+@@ -0,0 +1,34 @@
++Battle.net
++==========
++
++Blizzard implemented OAuth2 protocol for their authentication mechanism. To
++enable ``python-social-auth`` support follow this steps:
++
++1. Go to `Battlenet Developer Portal`_ and create an application.
++
++2. Fill App Id and Secret in your project settings::
++
++	SOCIAL_AUTH_BATTLENET_OAUTH2_KEY = '...'
++	SOCIAL_AUTH_BATTLENET_OAUTH2_SECRET = '...'
++
++3. Enable the backend::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.battlenet.BattleNetOAuth2',
++        ...
++    )
++
++Note: If you want to allow the user to choose a username from his own
++characters, some further steps are required, see the use cases part of the
++documentation. To get the account id and battletag use the user_data function, as
++`account id is no longer passed inherently`_.
++
++Another note: If you get a 500 response "Internal Server Error" the API now requires `https on callback endpoints`_.
++
++Further documentation at `Developer Guide`_.
++
++.. _Battlenet Developer Portal: https://dev.battle.net/
++.. _Developer Guide: https://dev.battle.net/docs/read/oauth
++.. _https on callback endpoints: http://us.battle.net/en/forum/topic/17085510584
++.. _account id is no longer passed inherently: http://us.battle.net/en/forum/topic/18300183303
+--- /dev/null
++++ b/docs/backends/beats.rst
+@@ -0,0 +1,25 @@
++Beats
++=====
++
++Beats supports OAuth 2.
++
++- Register a new application at `Beats Music API`_, and follow the
++  instructions below.
++  
++OAuth2
++------
++
++Add the Beats OAuth2 backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.beats.BeatsOAuth2',
++        ...
++    )
++
++- Fill ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_BEATS_OAUTH2_KEY = ''
++      SOCIAL_AUTH_BEATS_OAUTH2_SECRET = ''
++
++.. _Beats Music API: https://developer.beatsmusic.com/docs
+--- /dev/null
++++ b/docs/backends/behance.rst
+@@ -0,0 +1,31 @@
++Behance
++=======
++
++DEPRECATED NOTICE
++-----------------
++
++**NOTE:** IT SEEMS THAT BEHANCE HAS DROPPED THEIR OAUTH2 SUPPORT WITHOUT MUCH
++NOTICE BESIDE A `BLOG POST`_ ON SEPTEMBER 2014 MENTIONING THAT IT WILL BE
++INTRODUCED "SOON". THIS BACKEND IS IN DEPRECATED STATE FOR NOW.
++
++Behance uses OAuth2 for its auth mechanism.
++
++- Register a new application at `Behance App Registration`_, set your
++  application name, website and redirect URI.
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_BEHANCE_KEY = ''
++      SOCIAL_AUTH_BEHANCE_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++     SOCIAL_AUTH_BEHANCE_SCOPE = [...]
++
++Check available permissions at `Possible Scopes`_. Also check the rest of their
++doc at `Behance Developer Documentation`_.
++
++.. _Behance App Registration: http://www.behance.net/dev/register
++.. _Possible Scopes: http://www.behance.net/dev/authentication#scopes
++.. _Behance Developer Documentation: http://www.behance.net/dev
++.. _BLOG POST: http://blog.behance.net/dev/introducing-the-behance-api
+--- /dev/null
++++ b/docs/backends/belgium_eid.rst
+@@ -0,0 +1,11 @@
++Belgium EID
++===========
++
++Belgium EID OpenId doesn't require major settings beside being defined on
++``AUTHENTICATION_BACKENDS```::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.belgiumeid.BelgiumEIDOpenId',
++        ...
++    )
+--- /dev/null
++++ b/docs/backends/bitbucket.rst
+@@ -0,0 +1,56 @@
++Bitbucket
++=========
++
++Bitbucket supports both OAuth2 and OAuth1 logins.
++
++1. Register a new OAuth Consumer by following the instructions in the
++   Bitbucket documentation: `OAuth on Bitbucket`_
++
++   Note: For OAuth2, your consumer MUST have the "account" scope otherwise
++   the user profile information (username, name, etc.) won't be accessible.
++
++2. Configure the appropriate settings for OAuth2 or OAuth1 (see below).
++
++
++OAuth2
++------
++
++- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings::
++
++    SOCIAL_AUTH_BITBUCKET_OAUTH2_KEY = '<your-consumer-key>'
++    SOCIAL_AUTH_BITBUCKET_OAUTH2_SECRET = '<your-consumer-secret>'
++
++- If you would like to restrict access to only users with verified e-mail
++  addresses, set ``SOCIAL_AUTH_BITBUCKET_OAUTH2_VERIFIED_EMAILS_ONLY = True``
++  By default the setting is set to ``False`` since it's possible for a
++  project to gather this information by other methods.
++
++  
++OAuth1
++------
++
++- OAuth1 works similarly to OAuth2, but you must fill in the following settings
++  instead::
++
++    SOCIAL_AUTH_BITBUCKET_KEY = '<your-consumer-key>'
++    SOCIAL_AUTH_BITBUCKET_SECRET = '<your-consumer-secret>'
++
++- If you would like to restrict access to only users with verified e-mail
++  addresses, set ``SOCIAL_AUTH_BITBUCKET_VERIFIED_EMAILS_ONLY = True``.
++  By default the setting is set to ``False`` since it's possible for a
++  project to gather this information by other methods.
++
++
++User ID
++-------
++
++Bitbucket recommends the use of UUID_ as the user identifier instead
++of ``username`` since they can change and impose a security risk. For
++that reason ``UUID`` is used by default, but for backward
++compatibility reasons, it's possible to get the old behavior again by
++defining this setting::
++
++    SOCIAL_AUTH_BITBUCKET_USERNAME_AS_ID = True
++
++.. _UUID: https://confluence.atlassian.com/display/BITBUCKET/Use+the+Bitbucket+REST+APIs
++.. _OAuth on Bitbucket: https://confluence.atlassian.com/display/BITBUCKET/OAuth+on+Bitbucket
+--- /dev/null
++++ b/docs/backends/box.rst
+@@ -0,0 +1,23 @@
++Box.net
++=======
++
++Box works similar to Facebook (OAuth2).
++
++- Register an application at `Manage Box Applications`_
++
++- Fill the **Consumer Key** and **Consumer Secret** values in your settings::
++
++    SOCIAL_AUTH_BOX_KEY = ''
++    SOCIAL_AUTH_BOX_SECRET = ''
++
++- By default the token is not permanent, it will last an hour. To refresh the
++  access token just do::
++
++    from social.apps.django_app.utils import load_strategy
++
++    strategy = load_strategy(backend='box')
++    user = User.objects.get(pk=foo)
++    social = user.social_auth.filter(provider='box')[0]
++    social.refresh_token(strategy=strategy)
++
++.. _Manage Box Applications: https://app.box.com/developers/services
+--- /dev/null
++++ b/docs/backends/changetip.rst
+@@ -0,0 +1,22 @@
++ChangeTip
++=========
++
++ChangeTip
++
++- Register a new application at ChangeTip_, set the callback URL to
++  ``http://example.com/complete/changetip/`` replacing ``example.com`` with your
++  domain.
++
++- Fill ``Client ID`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_CHANGETIP_KEY = ''
++      SOCIAL_AUTH_CHANGETIP_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_CHANGETIP_SCOPE = [...]
++
++  See auth scopes at `ChangeTip OAuth docs`_.
++
++.. _ChangeTip: https://www.changetip.com/api
++.. _ChangeTip OAuth docs: https://www.changetip.com/api/auth/#!#scopes
+--- /dev/null
++++ b/docs/backends/clef.rst
+@@ -0,0 +1,15 @@
++Clef
++======
++
++Clef works similar to Facebook (OAuth).
++
++- Register a new application at `Clef Developers`_, set the callback URL to
++  ``http://example.com/complete/clef/`` replacing ``example.com`` with your
++  domain.
++
++- Fill ``App Id`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_CLEF_KEY = ''
++      SOCIAL_AUTH_CLEF_SECRET = ''
++
++.. _Clef Developers: https://getclef.com/developer
+\ No newline at end of file
+--- /dev/null
++++ b/docs/backends/coinbase.rst
+@@ -0,0 +1,22 @@
++Coinbase
++========
++
++Coinbase uses OAuth2.
++
++- Register an application at Coinbase_
++
++- Fill in the **Client Id** and **Client Secret** values in your settings::
++
++    SOCIAL_AUTH_COINBASE_KEY = ''
++    SOCIAL_AUTH_COINBASE_SECRET = ''
++    
++- Set the ``redirect_url`` on coinbase. Make sure to include the trailing
++  slash, eg. ``http://hostname/complete/coinbase/``
++
++- Specify scopes with::
++
++    SOCIAL_AUTH_COINBASE_SCOPE = [...]
++    
++  By default the scope is set to ``balance``.
++
++.. _Coinbase: https://coinbase.com/oauth/applications
+--- /dev/null
++++ b/docs/backends/coursera.rst
+@@ -0,0 +1,26 @@
++Coursera
++============
++
++Coursera uses a variant of OAuth2 authentication. The details of the API
++can be found at `OAuth2-based APIs - Coursera Technology`_.
++
++Take the following steps in order to use the backend:
++
++1. Create an account at `Coursera`_.
++
++2. Open `Developer Console`_, create an organisation and application.
++
++3. Set **Client ID** as a ``SOCIAL_AUTH_COURSERA_KEY`` and
++**Secret Key** as a ``SOCIAL_AUTH_COURSERA_SECRET`` in your local settings.
++
++4. Add the backend to ``AUTHENTICATION_BACKENDS`` setting::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.coursera.CourseraOAuth2',
++        ...
++    )
++
++.. _OAuth2-based APIs - Coursera Technology: https://tech.coursera.org/app-platform/oauth2/
++.. _Coursera: https://accounts.coursera.org/console
++.. _Developer Console: https://accounts.coursera.org/console
+--- /dev/null
++++ b/docs/backends/dailymotion.rst
+@@ -0,0 +1,23 @@
++DailyMotion
++===========
++
++DailyMotion uses OAuth2. In order to enable the backend follow:
++
++- Register an application at `DailyMotion Developer Portal`_
++
++- Fill in the **Client Id** and **Client Secret** values in your settings::
++
++    SOCIAL_AUTH_DAILYMOTION_KEY = ''
++    SOCIAL_AUTH_DAILYMOTION_SECRET = ''
++    
++- Set the ``Callback URL`` to ``http://<your hostname>/complete/dailymotion/``
++
++- Specify scopes with::
++
++    SOCIAL_AUTH_DAILYMOTION_SCOPE = [...]
++    
++  Available scopes are listed in the `Requesting Extended Permissions`_
++  section.
++
++.. _DailyMotion Developer Portal: http://www.dailymotion.com/profile/developer/new
++.. _Requesting Extended Permissions: http://www.dailymotion.com/doc/api/authentication.html#requesting-extended-permissions
+--- /dev/null
++++ b/docs/backends/digitalocean.rst
+@@ -0,0 +1,24 @@
++DigitalOcean
++============
++
++DigitalOcean uses OAuth2 for its auth process. See the full `DigitalOcean
++developer's documentation`_ for more information.
++
++- Register a new application in the `Apps & API page`_ in the DigitalOcean
++  control panel, setting the callback URL to ``http://example.com/complete/digitalocean/``
++  replacing ``example.com`` with your domain.
++
++- Fill the ``Client ID`` and ``Client Secret`` values from GitHub in the settings::
++
++      SOCIAL_AUTH_DIGITALOCEAN_KEY = ''
++      SOCIAL_AUTH_DIGITALOCEAN_SECRET = ''
++
++- By default, only ``read`` permissions are granted. In order to create,
++  destroy, and take other actions on the user's resources, you must request
++  ``read write`` permissions like so::
++
++      SOCIAL_AUTH_DIGITALOCEAN_AUTH_EXTRA_ARGUMENTS = {'scope': 'read write'}
++
++
++.. _DigitalOcean developer's documentation: https://developers.digitalocean.com/documentation/
++.. _Apps & API page: https://cloud.digitalocean.com/settings/applications
+--- /dev/null
++++ b/docs/backends/disqus.rst
+@@ -0,0 +1,20 @@
++Disqus
++======
++
++Disqus uses OAuth v2 for Authentication.
++
++- Register a new application at the `Disqus API`_, and
++
++- fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_DISQUS_KEY = ''
++      SOCIAL_AUTH_DISQUS_SECRET = ''
++
++- extra scopes can be defined by using::
++
++    SOCIAL_AUTH_DISQUS_AUTH_EXTRA_ARGUMENTS = {'scope': 'likes comments relationships'}
++
++  Check `Disqus Auth API`_ for details.
++
++.. _Disqus Auth API: http://disqus.com/api/docs/auth/
++.. _Disqus API: http://disqus.com/api/applications/
+--- /dev/null
++++ b/docs/backends/docker.rst
+@@ -0,0 +1,20 @@
++Docker
++======
++
++Docker.io OAuth2
++----------------
++
++Docker.io now supports OAuth2 for their API. In order to set it up:
++
++- Register a new application by following the instructions in their website:
++  `Register Your Application`_
++
++- Fill **Consumer Key** and **Consumer Secret** values in settings::
++
++      SOCIAL_AUTH_DOCKER_KEY = ''
++      SOCIAL_AUTH_DOCKER_SECRET = ''
++
++- Add ``'social.backends.docker.DockerOAuth2'`` into your
++  ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``.
++
++.. _Register Your Application: http://docs.docker.io/en/latest/reference/api/docker_io_oauth_api/#register-your-application
+--- /dev/null
++++ b/docs/backends/douban.rst
+@@ -0,0 +1,47 @@
++Douban
++======
++
++Douban supports OAuth 1 and 2.
++
++Douban OAuth1
++-------------
++
++Douban OAuth 1 works similar to Twitter OAuth.
++
++Douban offers per application keys named ``Consumer Key`` and ``Consumer
++Secret``. To enable Douban OAuth these two keys are needed. Further
++documentation at `Douban Services & API`_:
++
++- Register a new application at `Douban API Key`_, make sure to mark the **web
++  application** checkbox.
++
++- Fill **Consumer Key** and **Consumer Secret** values in settings::
++
++      SOCIAL_AUTH_DOUBAN_KEY = ''
++      SOCIAL_AUTH_DOUBAN_SECRET = ''
++
++- Add ``'social.backends.douban.DoubanOAuth'`` into your
++  ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``.
++
++
++Douban OAuth2
++-------------
++
++Recently Douban launched their OAuth2 support and the new developer site, you
++can find documentation at `Douban Developers`_. To setup OAuth2 follow:
++
++- Register a new application at `Create A Douban App`_, make sure to mark the
++  **web application** checkbox.
++
++- Fill **Consumer Key** and **Consumer Secret** values in settings::
++
++      SOCIAL_AUTH_DOUBAN_OAUTH2_KEY = ''
++      SOCIAL_AUTH_DOUBAN_OAUTH2_SECRET = ''
++
++- Add ``'social.backends.douban.DoubanOAuth2'`` into your
++  ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``.
++
++.. _Douban Services & API: http://www.douban.com/service/
++.. _Douban API Key: http://www.douban.com/service/apikey/apply
++.. _Douban Developers: http://developers.douban.com/
++.. _Create A Douban App : http://developers.douban.com/apikey/apply
+--- /dev/null
++++ b/docs/backends/dribbble.rst
+@@ -0,0 +1,23 @@
++Dribbble
++========
++
++Dribbble
++
++- Register a new application at Dribbble_, set the callback URL
++  to ``http://example.com/complete/dribbble/`` replacing
++  ``example.com`` with your domain.
++
++- Fill ``Client ID`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_DRIBBBLE_KEY = ''
++      SOCIAL_AUTH_DRIBBBLE_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_DRIBBBLE_SCOPE = [...]
++
++  See auth scopes at `Dribbble Developer docs`_.
++
++
++.. _Dribbble: https://dribbble.com/account/applications/new
++.. _Dribbble Developer docs: http://developer.dribbble.com/v1/oauth/
+--- /dev/null
++++ b/docs/backends/drip.rst
+@@ -0,0 +1,14 @@
++Drip
++====
++
++Drip uses OAuth v2 for Authentication.
++
++- Register a new application with `Drip`_, and
++
++- fill ``Client ID`` and ``Client Secret`` from getdrip.com values in
++  the settings::
++
++      SOCIAL_AUTH_DRIP_KEY = ''
++      SOCIAL_AUTH_DRIP_SECRET = ''
++
++.. _Drip: https://www.getdrip.com/user/applications
+--- /dev/null
++++ b/docs/backends/dropbox.rst
+@@ -0,0 +1,42 @@
++Dropbox
++=======
++
++Dropbox supports both OAuth 1 and 2.
++
++- Register a new application at `Dropbox Developers`_, and follow the
++  instructions below for the version of OAuth for which you are adding
++  support.
++
++OAuth1
++------
++
++Add the Dropbox OAuth backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.dropbox.DropboxOAuth',
++        ...
++    )
++
++- Fill ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_DROPBOX_KEY = ''
++      SOCIAL_AUTH_DROPBOX_SECRET = ''
++
++OAuth2
++------
++
++Add the Dropbox OAuth2 backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.dropbox.DropboxOAuth2',
++        ...
++    )
++
++- Fill ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_DROPBOX_OAUTH2_KEY = ''
++      SOCIAL_AUTH_DROPBOX_OAUTH2_SECRET = ''
++
++.. _Dropbox Developers: https://www.dropbox.com/developers/apps
+--- /dev/null
++++ b/docs/backends/edmodo.rst
+@@ -0,0 +1,22 @@
++Edmodo
++======
++
++Edmodo supports OAuth 2.
++
++- Register a new application at `Edmodo Connect API`_, and follow the
++  instructions below.
++- Add the Edmodo OAuth2 backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.edmodo.EdmodoOAuth2',
++        ...
++    )
++
++- Fill ``App Key``, ``App Secret`` and ``App Scope`` values in the settings::
++
++      SOCIAL_AUTH_EDMODO_OAUTH2_KEY = ''
++      SOCIAL_AUTH_EDMODO_OAUTH2_SECRET = ''
++      SOCIAL_AUTH_EDMODO_SCOPE = ['basic']
++
++.. _Edmodo Connect API: https://developers.edmodo.com/edmodo-connect/edmodo-connect-overview-getting-started/
+--- /dev/null
++++ b/docs/backends/email.rst
+@@ -0,0 +1,58 @@
++Email Auth
++==========
++
++python-social-auth_ comes with an EmailAuth_ backend which comes handy when
++your site uses requires the plain old email and password authentication
++mechanism.
++
++Actually that's a lie since the backend doesn't handle password at all, that's
++up to the developer to validate the password in and the proper place to do it
++is the pipeline, right after the user instance was retrieved or created.
++
++The reason to leave password handling to the developer is because too many
++things are really tied to the project, like the field where the password is
++stored, salt handling, password hashing algorithm and validation. So just add
++the pipeline functions that will do that following the needs of your project.
++
++
++Backend settings
++----------------
++
++``SOCIAL_AUTH_EMAIL_FORM_URL = '/login-form/'``
++    Used to redirect the user to the login/signup form, it must have at least
++    one field named ``email``. Form submit should go to ``/complete/email``,
++    or if it goes to your view, then your view should complete the process
++    calling ``social.actions.do_complete``.
++
++``SOCIAL_AUTH_EMAIL_FORM_HTML = 'login_form.html'``
++    The template will be used to render the login/signup form to the user, it
++    must have at least one field named ``email``. Form submit should go to
++    ``/complete/email``, or if it goes to your view, then your view should
++    complete the process calling ``social.actions.do_complete``.
++
++
++Email validation
++----------------
++
++Check *Email validation* pipeline in the `pipeline docs`_.
++
++Password handling
++-----------------
++
++Here's an example of password handling to add to the pipeline::
++
++    def user_password(strategy, backend, user, is_new=False, *args, **kwargs):
++        if backend.name != 'email':
++            return
++
++        password = strategy.request_data()['password']
++        if is_new:
++            user.set_password(password)
++            user.save()
++        elif not user.validate_password(password):
++            # return {'user': None, 'social': None}
++            raise AuthForbidden(backend)
++
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _EmailAuth: https://github.com/omab/python-social-auth/blob/master/social/backends/email.py#L5
++.. _pipeline docs: ../pipeline.html#email-validation
+--- /dev/null
++++ b/docs/backends/eveonline.rst
+@@ -0,0 +1,23 @@
++EVE Online Single Sign-On (SSO)
++===============================
++
++The EVE Single Sign-On (SSO) works similar to GitHub (OAuth2).
++
++- Register a new application at `EVE Developers`_, set the callback URL to
++  ``http://example.com/complete/eveonline/`` replacing ``example.com`` with your
++  domain.
++
++- Fill the ``Client ID`` and ``Secret Key`` values from EVE Developers in the settings::
++
++      SOCIAL_AUTH_EVEONLINE_KEY = ''
++      SOCIAL_AUTH_EVEONLINE_SECRET = ''
++
++- If you want to use EVE Character names as user names, use this setting::
++
++      SOCIAL_AUTH_CLEAN_USERNAMES = False
++
++- If you want to access EVE Online's CREST API, use::
++
++      SOCIAL_AUTH_EVEONLINE_SCOPE = ['publicData']
++
++.. _EVE Developers: https://developers.eveonline.com/
+--- /dev/null
++++ b/docs/backends/evernote.rst
+@@ -0,0 +1,24 @@
++Evernote OAuth
++==============
++
++Evernote OAuth 1.0 for its authentication workflow.
++
++- Register a new application at `Evernote API Key form`_.
++
++- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings::
++
++      SOCIAL_AUTH_EVERNOTE_KEY = ''
++      SOCIAL_AUTH_EVERNOTE_SECRET = ''
++
++
++Sandbox
++-------
++
++Evernote supports a sandbox mode for testing, there's a custom backend for it
++which name is ``evernote-sandbox`` instead of ``evernote``. Same settings apply
++but use these instead::
++
++      SOCIAL_AUTH_EVERNOTE_SANDBOX_KEY = ''
++      SOCIAL_AUTH_EVERNOTE_SANDBOX_SECRET = ''
++
++.. _Evernote API Key form: http://dev.evernote.com/support/api_key.php
+--- /dev/null
++++ b/docs/backends/facebook.rst
+@@ -0,0 +1,91 @@
++Facebook
++========
++
++OAuth2
++------
++
++Facebook uses OAuth2 for its auth process. Further documentation at `Facebook
++development resources`_:
++
++- Register a new application at `Facebook App Creation`_, don't use
++  ``localhost`` as ``App Domains`` and ``Site URL`` since Facebook won't allow
++  them. Use a placeholder like ``myapp.com`` and define that domain in your
++  ``/etc/hosts`` or similar file.
++
++- fill ``App Id`` and ``App Secret`` values in values::
++
++      SOCIAL_AUTH_FACEBOOK_KEY = ''
++      SOCIAL_AUTH_FACEBOOK_SECRET = ''
++
++- Define ``SOCIAL_AUTH_FACEBOOK_SCOPE`` to get extra permissions
++  from facebook. Email is not sent by default, to get it, you must request the
++  ``email`` permission::
++
++     SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
++
++- Define ``SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS`` to pass extra parameters
++  to https://graph.facebook.com/me when gathering the user profile data (you need
++  to explicitly ask for fields like ``email`` using ``fields`` key)::
++
++    SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
++      'locale': 'ru_RU',
++      'fields': 'id, name, email, age_range'
++    }
++
++If you define a redirect URL in Facebook setup page, be sure to not define
++http://127.0.0.1:8000 or http://localhost:8000 because it won't work when
++testing. Instead I define http://myapp.com and setup a mapping on ``/etc/hosts``.
++
++
++Canvas Application
++------------------
++
++If you need to perform authentication from Facebook Canvas application:
++
++- Create your canvas application at http://developers.facebook.com/apps
++
++- In Facebook application settings specify your canvas URL ``mysite.com/fb``
++  (current default)
++
++- Setup your Python Social Auth settings and your application namespace::
++
++    SOCIAL_AUTH_FACEBOOK_APP_KEY = ''
++    SOCIAL_AUTH_FACEBOOK_APP_SECRET = ''
++    SOCIAL_AUTH_FACEBOOK_APP_NAMESPACE = ''
++
++- Launch your testing server on port 80 (use sudo or nginx or apache) for
++  browser to be able to load it when Facebook calls canvas URL
++
++- Open your Facebook page via http://apps.facebook.com/app_namespace or
++  better via http://www.facebook.com/pages/user-name/user-id?sk=app_app-id
++
++- After that you will see this page in a right way and will able to connect
++  to application and login automatically after connection
++
++- Provide a template to be rendered, it must have this JavaScript snippet (or
++  similar) in it::
++
++    <script type="text/javascript">
++        var domain = 'https://apps.facebook.com/',
++            redirectURI = domain + {{ FACEBOOK_APP_NAMESPACE }} + '/';
++
++        window.top.location = 'https://www.facebook.com/dialog/oauth/' +
++                                    '?client_id={{ FACEBOOK_KEY }}' +
++                                    '&redirect_uri=' + encodeURIComponent(redirectURI) +
++                                    '&scope={{ FACEBOOK_EXTENDED_PERMISSIONS }}';
++    </script>
++
++
++More info on the topic at `Facebook Canvas Application Authentication`_.
++
++
++Graph 2.0
++---------
++
++If looking for `Graph 2.0`_ support, use the backends ``Facebook2OAuth2``
++(OAuth2) and/or ``Facebook2AppOAuth2`` (Canvas application).
++
++.. _Facebook development resources: http://developers.facebook.com/docs/authentication/
++.. _Facebook App Creation: http://developers.facebook.com/setup/
++.. _Facebook Canvas Application Authentication: http://www.ikrvss.ru/2011/09/22/django-social-auth-and-facebook-canvas-applications/
++.. _Graph 2.0: https://developers.facebook.com/blog/post/2014/04/30/the-new-facebook-login/
+--- /dev/null
++++ b/docs/backends/fedora.rst
+@@ -0,0 +1,11 @@
++Fedora
++======
++
++Fedora OpenId doesn't require major settings beside being defined on
++``AUTHENTICATION_BACKENDS```::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.fedora.FedoraOpenId',
++        ...
++    )
+--- /dev/null
++++ b/docs/backends/fitbit.rst
+@@ -0,0 +1,42 @@
++Fitbit
++======
++
++Fitbit supports both OAuth 2.0 and OAuth 1.0a logins. OAuth 2 is
++preferred for new integrations, as OAuth 1.0a does not support getting
++heartrate or location and will be deprecated in the future.
++
++1. Register a new OAuth Consumer `here`_
++
++2. Configure the appropriate settings for OAuth 2.0 or OAuth 1.0a (see
++   below).
++
++OAuth 2.0 or OAuth 1.0a
++-----------------------
++
++- Fill ``Consumer Key`` and ``Consumer Secret`` values in the
++  settings::
++
++    SOCIAL_AUTH_FITBIT_KEY = '<your-consumer-key>'
++    SOCIAL_AUTH_FITBIT_SECRET = '<your-consumer-secret>'
++
++OAuth 2.0 specific settings
++---------------------------
++
++By default, only the ``profile`` scope is requested. To request more
++scopes, set SOCIAL_AUTH_FITBIT_SCOPE::
++
++    SOCIAL_AUTH_FITBIT_SCOPE = [
++      'activity',
++      'heartrate',
++      'location',
++      'nutrition',
++      'profile',
++      'settings',
++      'sleep',
++      'social',
++      'weight'
++    ]
++
++The above will request all permissions from the user.
++
++.. _here: https://dev.fitbit.com/apps/new
+--- /dev/null
++++ b/docs/backends/flickr.rst
+@@ -0,0 +1,19 @@
++Flickr
++======
++
++Flickr uses OAuth v1.0 for authentication.
++
++- Register a new application at the `Flickr App Garden`_, and
++
++- fill ``Key`` and ``Secret`` values in the settings::
++
++      SOCIAL_AUTH_FLICKR_KEY = ''
++      SOCIAL_AUTH_FLICKR_SECRET = ''
++
++- Flickr might show a messages saying "Oops! Flickr doesn't recognise the
++  permission set.", if encountered with this error, just define this setting::
++
++    SOCIAL_AUTH_FLICKR_AUTH_EXTRA_ARGUMENTS = {'perms': 'read'}
++
++
++.. _Flickr App Garden: http://www.flickr.com/services/apps/create/
+--- /dev/null
++++ b/docs/backends/foursquare.rst
+@@ -0,0 +1,14 @@
++Foursquare
++==========
++
++Foursquare uses OAuth2. In order to enable the backend follow:
++
++- Register an application at `Foursquare Developers Portal`_,
++  set the ``Redirect URI`` to ``http://<your hostname>/complete/foursquare/``
++
++- Fill in the **Client Id** and **Client Secret** values in your settings::
++
++    SOCIAL_AUTH_FOURSQUARE_KEY = ''
++    SOCIAL_AUTH_FOURSQUARE_SECRET = ''
++    
++.. _Foursquare Developers Portal: https://foursquare.com/developers/register
+--- /dev/null
++++ b/docs/backends/github.rst
+@@ -0,0 +1,61 @@
++GitHub
++======
++
++GitHub works similar to Facebook (OAuth).
++
++- Register a new application at `GitHub Developers`_, set the callback URL to
++  ``http://example.com/complete/github/`` replacing ``example.com`` with your
++  domain.
++
++- Fill the ``Client ID`` and ``Client Secret`` values from GitHub in the settings::
++
++      SOCIAL_AUTH_GITHUB_KEY = ''
++      SOCIAL_AUTH_GITHUB_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_GITHUB_SCOPE = [...]
++
++
++GitHub for Organizations
++------------------------
++
++When defining authentication for organizations, use the
++``GithubOrganizationOAuth2`` backend instead. The settings are the same as
++the non-organization backend, but the names must be::
++
++      SOCIAL_AUTH_GITHUB_ORG_*
++
++Be sure to define the organization name using the setting::
++
++      SOCIAL_AUTH_GITHUB_ORG_NAME = ''
++
++This name will be used to check that the user really belongs to the given
++organization and discard it if they're not part of it.
++
++
++GitHub for Teams
++----------------
++
++Similar to ``GitHub for Organizations``, there's a GitHub for Teams backend,
++use the backend ``GithubTeamOAuth2``. The settings are the same as
++the basic backend, but the names must be::
++
++    SOCIAL_AUTH_GITHUB_TEAM_*
++
++Be sure to define the ``Team ID`` using the setting::
++
++      SOCIAL_AUTH_GITHUB_TEAM_ID = ''
++
++This ``id`` will be used to check that the user really belongs to the given
++team and discard it if they're not part of it.
++
++
++Github for Enterprises
++----------------------
++
++Check the docs :ref:`github-enterprise` if planning to use Github
++Enterprises.
++
++
++.. _GitHub Developers: https://github.com/settings/applications/new
+--- /dev/null
++++ b/docs/backends/github_enterprise.rst
+@@ -0,0 +1,59 @@
++.. _github-enterprise:
++
++GitHub Enterprise
++=================
++
++GitHub Enterprise works similar to regular Github, which is in turn based on Facebook (OAuth).
++
++- Register a new application on your instance of `GitHub Enterprise Developers`_,
++  set the callback URL to ``http://example.com/complete/github/`` replacing ``example.com``
++  with your domain.
++
++- Set the API URL for your Github Enterprise appliance:
++
++      SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL = 'https://git.example.com/api/v3/'
++
++- Fill the ``Client ID`` and ``Client Secret`` values from GitHub in the settings:
++
++      SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY = ''
++      SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_GITHUB_ENTERPRISE_SCOPE = [...]
++
++
++GitHub Enterprise for Organizations
++-----------------------------------
++
++When defining authentication for organizations, use the
++``GithubEnterpriseOrganizationOAuth2`` backend instead. The settings are the same as
++the non-organization backend, but the names must be::
++
++      SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_*
++
++Be sure to define the organization name using the setting::
++
++      SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME = ''
++
++This name will be used to check that the user really belongs to the given
++organization and discard it if they're not part of it.
++
++
++GitHub Enterprise for Teams
++---------------------------
++
++Similar to ``GitHub Enterprise for Organizations``, there's a GitHub for Teams backend,
++use the backend ``GithubEnterpriseTeamOAuth2``. The settings are the same as
++the basic backend, but the names must be::
++
++    SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_*
++
++Be sure to define the ``Team ID`` using the setting::
++
++      SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID = ''
++
++This ``id`` will be used to check that the user really belongs to the given
++team and discard it if they're not part of it.
++
++.. _GitHub Enterprise Developers: https://<your_github_enterprise_domain>/settings/applications/new
+--- /dev/null
++++ b/docs/backends/google.rst
+@@ -0,0 +1,252 @@
++Google
++======
++
++This section describes how to setup the different services provided by Google.
++
++Google OAuth
++------------
++
++.. attention:: **Google OAuth deprecation**
++   Important: OAuth 1.0 was officially deprecated on April 20, 2012, and will be
++   shut down on April 20, 2015. We encourage you to migrate to any of the other
++   protocols.
++
++Google provides ``Consumer Key`` and ``Consumer Secret`` keys to registered
++applications, but also allows unregistered application to use their authorization
++system with, but beware that this method will display a security banner to the
++user telling that the application is not trusted.
++
++Check `Google OAuth`_ and make your choice.
++
++- fill ``Consumer Key`` and ``Consumer Secret`` values::
++
++      SOCIAL_AUTH_GOOGLE_OAUTH_KEY = ''
++      SOCIAL_AUTH_GOOGLE_OAUTH_SECRET = ''
++
++anonymous values will be used if not configured as described in their
++`OAuth reference`_
++
++- setup any needed extra scope in::
++
++      SOCIAL_AUTH_GOOGLE_OAUTH_SCOPE = [...]
++
++
++Google OAuth2
++-------------
++
++Recently Google launched OAuth2 support following the definition at `OAuth2 draft`.
++It works in a similar way to plain OAuth mechanism, but developers **must** register
++an application and apply for a set of keys. Check `Google OAuth2`_ document for details.
++
++When creating the application in the Google Console be sure to fill the
++``PRODUCT NAME`` at ``API & auth -> Consent screen`` form.
++
++To enable OAuth2 support:
++
++- fill ``Client ID`` and ``Client Secret`` settings, these values can be obtained
++  easily as described on `OAuth2 Registering`_ doc::
++
++      SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = ''
++      SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = ''
++
++- setup any needed extra scope::
++
++      SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [...]
++
++Check which applications can be included in their `Google Data Protocol Directory`_
++
++
++Google+ Sign-In
++---------------
++
++`Google+ Sign In`_ works a lot like OAuth2, but most of the initial work is
++done by their Javascript which thens calls a defined handler to complete the
++auth process.
++
++* To enable the backend create an application using the `Google
++  console`_ and following the steps from the `official guide`_. Make
++  sure to enable the Google+ API in the console.
++
++* Fill in the key settings looking inside the Google console the subsection
++  ``Credentials`` inside ``API & auth``::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.google.GooglePlusAuth',
++    )
++
++    SOCIAL_AUTH_GOOGLE_PLUS_KEY = '...'
++    SOCIAL_AUTH_GOOGLE_PLUS_SECRET = '...'
++
++  ``SOCIAL_AUTH_GOOGLE_PLUS_KEY`` corresponds to the variable ``CLIENT ID``.
++  ``SOCIAL_AUTH_GOOGLE_PLUS_SECRET`` corresponds to the variable
++  ``CLIENT SECRET``.
++
++* Add the sign-in button to your template, you can use the SDK button
++  or add your own and attach the click handler to it (check `Google+ Identity Sign-In`_
++  documentation about it)::
++
++    <div id="google-plus-button">Google+ Sign In</div>
++
++* Add the Javascript snippet in the same template as above::
++
++    <script src="https://apis.google.com/js/api:client.js"></script>
++
++    <script type="text/javascript">
++      gapi.load('auth2', function () {
++        var auth2;
++
++        auth2 = gapi.auth2.init({
++          client_id: "<PUT SOCIAL_AUTH_GOOGLE_PLUS_KEY HERE>",
++          scope: "<PUT BACKEND SCOPE HERE>"
++        });
++
++        auth2.then(function () {
++          var button = document.getElementById("google-plus-button");
++          console.log("User is signed-in in Google+ platform?", auth2.isSignedIn.get() ? "Yes" : "No");
++
++          auth2.attachClickHandler(button, {}, function (googleUser) {
++            // Send access-token to backend to finish the authenticate
++            // with your application
++
++            var authResponse = googleUser.getAuthResponse();
++            var $form;
++            var $input;
++
++            $form = $("<form>");
++            $form.attr("action", "/complete/google-plus");
++            $form.attr("method", "post");
++            $input = $("<input>");
++            $input.attr("name", "access_token");
++            $input.attr("value", authResponse.access_token);
++            $form.append($input);
++            // Add csrf-token if needed
++            $(document.body).append($form);
++            $form.submit();
++          });
++        });
++      });
++    </script>
++
++* Logging out
++
++  Logging-out can be tricky when using the the platform SDK because it
++  can trigger an automatic sign-in when listening to the user status
++  change. With the method show above, that won't happen, but if the UI
++  depends more in the SDK values than the backend, then things can get
++  out of sync easilly. To prevent this, the user should be logged-out
++  from Google+ platform too. This can be accomplished by doing::
++
++    <script type="text/javascript">
++      gapi.load('auth2', function () {
++        var auth2;
++
++        auth2 = gapi.auth2.init({
++          client_id: "{{ plus_id }}",
++          scope: "{{ plus_scope }}"
++        });
++
++        auth2.then(function () {
++          if (auth2.isSignedIn.get()) {
++            $('#logout').on('click', function (event) {
++              event.preventDefault();
++              auth2.signOut().then(function () {
++                console.log("Logged out from Google+ platform");
++                document.location = "/logout";
++              });
++            });
++          }
++        });
++      });
++    </script>
++
++
++Google OpenId
++-------------
++
++Google OpenId works straightforward, not settings are needed. Domains or emails
++whitelists can be applied too, check the whitelists_ settings for details.
++
++
++Orkut
++-----
++
++As of September 30, 2014, Orkut has been `shut down`_.
++
++User identification
++-------------------
++
++Optional support for static and unique Google Profile ID identifiers instead of
++using the e-mail address for account association can be enabled with::
++
++      SOCIAL_AUTH_GOOGLE_OAUTH_USE_UNIQUE_USER_ID = True
++
++or::
++
++      SOCIAL_AUTH_GOOGLE_OAUTH2_USE_UNIQUE_USER_ID = True
++
++depending on the backends in use.
++
++
++Refresh Tokens
++--------------
++
++To get an OAuth2 refresh token along with the access token, you must pass an extra argument: ``access_type=offline``.
++To do this with Google+ sign-in::
++
++      SOCIAL_AUTH_GOOGLE_PLUS_AUTH_EXTRA_ARGUMENTS = {
++            'access_type': 'offline'
++      }
++
++
++Scopes deprecation
++------------------
++
++Google is deprecating the full-url scopes from `Sept 1, 2014`_ in favor of
++``Google+ API`` and the recently introduced shorter scopes names. But
++``python-social-auth`` already introduced the scopes change at e3525187_ which
++was released at ``v0.1.24``.
++
++But, to enable the new scopes the application requires ``Google+ API`` to be
++enabled in the `Google console`_ dashboard, the change is quick and quite
++simple, but if any developer desires to keep using the old scopes, it's
++possible with the following settings::
++
++    # Google OAuth2 (google-oauth2)
++    SOCIAL_AUTH_GOOGLE_OAUTH2_IGNORE_DEFAULT_SCOPE = True
++    SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
++        'https://www.googleapis.com/auth/userinfo.email',
++        'https://www.googleapis.com/auth/userinfo.profile'
++    ]
++
++    # Google+ SignIn (google-plus)
++    SOCIAL_AUTH_GOOGLE_PLUS_IGNORE_DEFAULT_SCOPE = True
++    SOCIAL_AUTH_GOOGLE_PLUS_SCOPE = [
++        'https://www.googleapis.com/auth/plus.login',
++        'https://www.googleapis.com/auth/userinfo.email',
++        'https://www.googleapis.com/auth/userinfo.profile'
++    ]
++
++To ease the change, the old API and scopes is still supported by the
++application, the new values are the default option but if having troubles
++supporting them you can default to the old values by defining this setting::
++
++    SOCIAL_AUTH_GOOGLE_OAUTH2_USE_DEPRECATED_API = True
++    SOCIAL_AUTH_GOOGLE_PLUS_USE_DEPRECATED_API = True
++
++.. _Google support: http://www.google.com/support/a/bin/answer.py?hl=en&answer=162105
++.. _Google OpenID: http://code.google.com/apis/accounts/docs/OpenID.html
++.. _Google OAuth: http://code.google.com/apis/accounts/docs/OAuth.html
++.. _Google OAuth2: http://code.google.com/apis/accounts/docs/OAuth2.html
++.. _OAuth2 Registering: http://code.google.com/apis/accounts/docs/OAuth2.html#Registering
++.. _OAuth2 draft: http://tools.ietf.org/html/draft-ietf-oauth-v2-10
++.. _OAuth reference: http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth
++.. _shut down: https://support.google.com/orkut/?csw=1#Authenticating
++.. _Google Data Protocol Directory: http://code.google.com/apis/gdata/docs/directory.html
++.. _whitelists: ../configuration/settings.html#whitelists
++.. _Google+ Sign In: https://developers.google.com/+/web/signin/
++.. _Google console: https://code.google.com/apis/console
++.. _official guide: https://developers.google.com/+/web/signin/#step_1_create_a_client_id_and_client_secret
++.. _Sept 1, 2014: https://developers.google.com/+/api/auth-migration#timetable
++.. _e3525187: https://github.com/omab/python-social-auth/commit/e35251878a88954cecf8e575eca27c63164b9f67
++.. _Google+ Identity Sign-In: https://developers.google.com/identity/sign-in/web/sign-in
+--- /dev/null
++++ b/docs/backends/implementation.rst
+@@ -0,0 +1,308 @@
++Adding a new backend
++====================
++
++Add new backends is quite easy, usually adding just a ``class`` with a couple
++settings and methods overrides to retrieve user data from services API. Follow
++the details below.
++
++
++Common attributes
++-----------------
++
++First, lets check the common attributes for all backend types.
++
++``name = ''``
++    Any backend needs a name, usually the popular name of the service is used,
++    like ``facebook``, ``twitter``, etc. It must be unique, otherwise another
++    backend can take precedence if it's listed before in
++    ``AUTHENTICATION_BACKENDS`` setting.
++
++``ID_KEY = None``
++    Defines the attribute in the service response that identifies the user as
++    unique in the service, the value is later stored in the ``uid`` attribute
++    in the ``UserSocialAuth`` instance.
++
++``REQUIRES_EMAIL_VALIDATION = False``
++    Flags the backend to enforce email validation during the pipeline (if the
++    corresponding pipeline ``social.pipeline.mail.mail_validation`` was
++    enabled).
++
++``EXTRA_DATA = None``
++    During the auth process some basic user data is returned by the provider or
++    retrieved by ``user_data()`` method which usually is used to call some API
++    on the provider to retrieve it. This data will be stored under
++    ``UserSocialAuth.extra_data`` attribute, but to make it accessible under
++    some common names on different providers, this attribute defines a list of
++    tuples in the form ``(name, alias)`` where ``name`` is the key in the user
++    data (which should be a ``dict`` instance) and ``alias`` is the name to
++    store it on ``extra_data``.
++
++
++OAuth
++-----
++
++OAuth1 and OAuth2 provide share some common definitions based on the shared
++behavior during the auth process, like a successful API response from
++``AUTHORIZATION_URL`` usually returns some basic user data like a user Id.
++
++
++Shared attributes
++*****************
++
++``name``
++    This defines the backend name and identifies it during the auth process.
++    The name is used in the URLs ``/login/<backend name>`` and
++    ``/complete/<backend name>``.
++
++``ID_KEY = 'id'``
++    Default key name where user identification field is defined, it's used on
++    auth process when some basic user data is returned. This Id is stored in
++    ``UserSocialAuth.uid`` field, this together the ``UserSocialAuth.provider``
++    field is used to unique identify a user association.
++
++``SCOPE_PARAMETER_NAME = 'scope'``
++    Scope argument is used to tell the provider the API endpoints you want to
++    call later, it's a permissions request granted over the ``access_token``
++    later retrieved. Default value is ``scope`` since that's usually the name
++    used in the URL parameter, but can be overridden if needed.
++
++``DEFAULT_SCOPE = None``
++    Some providers give nothing about the user but some basic data in required
++    like the user Id or an email address. Default scope attribute is used to
++    specify a default value for ``scope`` argument to request those extra used
++    bits.
++
++``SCOPE_SEPARATOR = ' '``
++    The ``scope`` argument is usually a list of permissions to request, the
++    list is joined used a separator, usually just a blank space, but differ
++    from provider to provider, override the default value with this attribute
++    if it differs.
++
++
++OAuth2
++******
++
++OAuth2 backends are fairly simple to implement; just a few settings, a method
++override and it's mostly ready to go.
++
++The key points on this backends are:
++
++``AUTHORIZATION_URL``
++    This is the entry point for the authorization mechanism, users must be
++    redirected to this URL, used on ``auth_url`` method which builds the
++    redirect address with ``AUTHORIZATION_URL`` plus some arguments
++    (``client_id``, ``redirect_uri``, ``response_type``, and ``state``).
++
++``ACCESS_TOKEN_URL``
++    Must point to the API endpoint that provides an ``access_token`` needed to
++    authenticate in users behalf on future API calls.
++
++``REFRESH_TOKEN_URL``
++    Some providers give the option to renew the ``access_token`` since they are
++    usually limited in time, once that time runs out, the token is invalidated
++    and cannot be used any more. This attribute should point to that API
++    endpoint.
++
++``RESPONSE_TYPE``
++    The response type expected on the auth process, default value is ``code``
++    as dictated by OAuth2 definition. Override it if default value doesn't fit
++    the provider implementation.
++
++``STATE_PARAMETER``
++    OAuth2 defines that an ``state`` parameter can be passed in order to
++    validate the process, it's kind of a CSRF check to avoid man in the middle
++    attacks. Some don't recognise it or don't return it which will make the
++    auth process invalid. Set this attribute to ``False`` in that case.
++
++``REDIRECT_STATE``
++    For those providers that don't recognise the ``state`` parameter, the app
++    can add a ``redirect_state`` argument to the ``redirect_uri`` to mimic it.
++    Set this value to ``False`` if the provider likes to verify the
++    ``redirect_uri`` value and this parameter invalidates that check.
++
++
++Example code::
++
++    from social.backends.oauth import BaseOAuth2
++
++    class GithubOAuth2(BaseOAuth2):
++        """Github OAuth authentication backend"""
++        name = 'github'
++        AUTHORIZATION_URL = 'https://github.com/login/oauth/authorize'
++        ACCESS_TOKEN_URL = 'https://github.com/login/oauth/access_token'
++        SCOPE_SEPARATOR = ','
++        EXTRA_DATA = [
++            ('id', 'id'),
++            ('expires', 'expires')
++        ]
++
++        def get_user_details(self, response):
++            """Return user details from Github account"""
++            return {'username': response.get('login'),
++                    'email': response.get('email') or '',
++                    'first_name': response.get('name')}
++
++        def user_data(self, access_token, *args, **kwargs):
++            """Loads user data from service"""
++            url = 'https://api.github.com/user?' + urlencode({
++                'access_token': access_token
++            })
++            try:
++                return json.load(self.urlopen(url))
++            except ValueError:
++                return None
++
++
++OAuth1
++******
++
++OAuth1 process is a bit more trickier, `Twitter Docs`_ explains it quite well.
++Beside the ``AUTHORIZATION_URL`` and ``ACCESS_TOKEN_URL`` attributes, a third
++one is needed used when starting the process.
++
++``REQUEST_TOKEN_URL = ''``
++    During the auth process an unauthorized token is needed to start the
++    process, later this token is exchanged for an ``access_token``. This
++    setting points to the API endpoint where that unauthorized token can be
++    retrieved.
++
++Example code::
++
++    from xml.dom import minidom
++
++    from social.backends.oauth import ConsumerBasedOAuth
++
++
++    class TripItOAuth(ConsumerBasedOAuth):
++        """TripIt OAuth authentication backend"""
++        name = 'tripit'
++        AUTHORIZATION_URL = 'https://www.tripit.com/oauth/authorize'
++        REQUEST_TOKEN_URL = 'https://api.tripit.com/oauth/request_token'
++        ACCESS_TOKEN_URL = 'https://api.tripit.com/oauth/access_token'
++        EXTRA_DATA = [('screen_name', 'screen_name')]
++
++        def get_user_details(self, response):
++            """Return user details from TripIt account"""
++            try:
++                first_name, last_name = response['name'].split(' ', 1)
++            except ValueError:
++                first_name = response['name']
++                last_name = ''
++            return {'username': response['screen_name'],
++                    'email': response['email'],
++                    'fullname': response['name'],
++                    'first_name': first_name,
++                    'last_name': last_name}
++
++        def user_data(self, access_token, *args, **kwargs):
++            """Return user data provided"""
++            url = 'https://api.tripit.com/v1/get/profile'
++            request = self.oauth_request(access_token, url)
++            content = self.fetch_response(request)
++            try:
++                dom = minidom.parseString(content)
++            except ValueError:
++                return None
++
++            return {
++                'id': dom.getElementsByTagName('Profile')[0].getAttribute('ref'),
++                'name': dom.getElementsByTagName(
++                    'public_display_name')[0].childNodes[0].data,
++                'screen_name': dom.getElementsByTagName(
++                    'screen_name')[0].childNodes[0].data,
++                'email': dom.getElementsByTagName(
++                    'is_primary')[0].parentNode.getElementsByTagName(
++                    'address')[0].childNodes[0].data,
++            }
++
++
++OpenId
++------
++
++OpenId is fair simpler that OAuth since it's used for authentication rather
++than authorization (regardless it's used for authorization too).
++
++A single attribute is usually needed, the authentication URL endpoint.
++
++``URL = ''``
++    OpenId endpoint where to redirect the user.
++
++Sometimes the URL is user dependant, like in myOpenId_ where the URL is
++``https://<user handler>.myopenid.com``. For those cases where the user must
++input it's handle (or full URL). The backend must override the ``openid_url()``
++method to retrieve it and return a full URL to where the user will be
++redirected.
++
++Example code::
++
++    from social.backends.open_id import OpenIdAuth
++    from social.exceptions import AuthMissingParameter
++
++
++    class LiveJournalOpenId(OpenIdAuth):
++        """LiveJournal OpenID authentication backend"""
++        name = 'livejournal'
++
++        def get_user_details(self, response):
++            """Generate username from identity url"""
++            values = super(LiveJournalOpenId, self).get_user_details(response)
++            values['username'] = values.get('username') or \
++                                 urlparse.urlsplit(response.identity_url)\
++                                            .netloc.split('.', 1)[0]
++            return values
++
++        def openid_url(self):
++            """Returns LiveJournal authentication URL"""
++            if not self.data.get('openid_lj_user'):
++                raise AuthMissingParameter(self, 'openid_lj_user')
++            return 'http://%s.livejournal.com' % self.data['openid_lj_user']
++
++
++Auth APIs
++---------
++
++For others authentication types, a ``BaseAuth`` class is defined to help. Those
++custom auth methods must override the ``auth_url()`` and ``auth_complete()``
++methods.
++
++Example code::
++
++    from google.appengine.api import users
++
++    from social.backends.base import BaseAuth
++    from social.exceptions import AuthException
++
++
++    class GoogleAppEngineAuth(BaseAuth):
++        """GoogleAppengine authentication backend"""
++        name = 'google-appengine'
++
++        def get_user_id(self, details, response):
++            """Return current user id."""
++            user = users.get_current_user()
++            if user:
++                return user.user_id()
++
++        def get_user_details(self, response):
++            """Return user basic information (id and email only)."""
++            user = users.get_current_user()
++            return {'username': user.user_id(),
++                    'email': user.email(),
++                    'fullname': '',
++                    'first_name': '',
++                    'last_name': ''}
++
++        def auth_url(self):
++            """Build and return complete URL."""
++            return users.create_login_url(self.redirect_uri)
++
++        def auth_complete(self, *args, **kwargs):
++            """Completes login process, must return user instance."""
++            if not users.get_current_user():
++                raise AuthException('Authentication error')
++            kwargs.update({'response': '', 'backend': self})
++            return self.strategy.authenticate(*args, **kwargs)
++
++
++.. _Twitter Docs: https://dev.twitter.com/docs/auth/implementing-sign-twitter
++.. _myOpenId: https://www.myopenid.com/
+--- /dev/null
++++ b/docs/backends/index.rst
+@@ -0,0 +1,156 @@
++Backends
++========
++
++Here's a list and detailed instruction on how to setup the support for each
++backend.
++
++Adding new backend support
++--------------------------
++
++Add new backends is quite easy, usually adding just a ``class`` with a couple
++methods overrides to retrieve user data from services API. Follow the details
++in the *Implementation* docs.
++
++.. toctree::
++   :maxdepth: 2
++
++   implementation
++
++
++Supported backends
++------------------
++
++Here's the list of currently supported backends.
++
++Non-social backends
++*******************
++
++.. toctree::
++   :maxdepth: 2
++
++   email
++   username
++
++Base OAuth and OpenId classes
++*****************************
++
++.. toctree::
++   :maxdepth: 2
++
++   oauth
++   openid
++   saml
++
++Social backends
++***************
++
++.. toctree::
++   :maxdepth: 2
++
++   amazon
++   angel
++   aol
++   appsfuel
++   arcgis
++   azuread
++   battlenet
++   beats
++   behance
++   belgium_eid
++   bitbucket
++   box
++   changetip
++   clef
++   coinbase
++   coursera
++   dailymotion
++   digitalocean
++   disqus
++   docker
++   douban
++   dribbble
++   drip
++   dropbox
++   edmodo
++   eveonline
++   evernote
++   facebook
++   fedora
++   fitbit
++   flickr
++   foursquare
++   github
++   github_enterprise
++   google
++   instagram
++   itembase
++   jawbone
++   justgiving
++   kakao
++   khanacademy
++   lastfm
++   launchpad
++   line
++   linkedin
++   livejournal
++   live
++   loginradius
++   mailru
++   mapmyfitness
++   meetup
++   mendeley
++   mineid
++   mixcloud
++   moves
++   naszaklasa
++   nationbuilder
++   naver
++   ngpvan_actionid
++   odnoklassnikiru
++   openstreetmap
++   orbi
++   persona
++   pinterest
++   pixelpin
++   pocket
++   podio
++   qiita
++   qq
++   rdio
++   readability
++   reddit
++   runkeeper
++   salesforce
++   shopify
++   sketchfab
++   skyrock
++   slack
++   soundcloud
++   spotify
++   suse
++   stackoverflow
++   steam
++   stocktwits
++   strava
++   stripe
++   taobao
++   thisismyjam
++   trello
++   tripit
++   tumblr
++   twilio
++   twitch
++   twitter
++   uber
++   untappd
++   upwork
++   vend
++   vimeo
++   vk
++   weibo
++   withings
++   wunderlist
++   xing
++   yahoo
++   yammer
++   zotero
+--- /dev/null
++++ b/docs/backends/instagram.rst
+@@ -0,0 +1,25 @@
++Instagram
++=========
++
++Instagram uses OAuth v2 for Authentication.
++
++- Register a new application at the `Instagram API`_, and
++
++- Add instagram backend to ``AUTHENTICATION_SETTINGS``::
++
++      AUTHENTICATION_SETTINGS = (
++        ...
++        'social.backends.instagram.InstagramOAuth2',
++        ...
++      )
++
++- fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_INSTAGRAM_KEY = ''
++      SOCIAL_AUTH_INSTAGRAM_SECRET = ''
++
++- extra scopes can be defined by using::
++
++    SOCIAL_AUTH_INSTAGRAM_AUTH_EXTRA_ARGUMENTS = {'scope': 'likes comments relationships'}
++
++.. _Instagram API: http://instagr.am/developer/
+--- /dev/null
++++ b/docs/backends/itembase.rst
+@@ -0,0 +1,51 @@
++Itembase
++=========
++
++Itembase uses OAuth2 for authentication.
++
++- Register a new application for the `Itembase API`_, and
++
++- Add itembase live backend and/or sandbox backend to ``AUTHENTICATION_BACKENDS``::
++
++      AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.itembase.ItembaseOAuth2',
++        'social.backends.itembase.ItembaseOAuth2Sandbox',
++        ...
++      )
++
++- fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++    SOCIAL_AUTH_ITEMBASE_KEY = ''
++    SOCIAL_AUTH_ITEMBASE_SECRET = ''
++
++    SOCIAL_AUTH_ITEMBASE_SANDBOX_KEY = ''
++    SOCIAL_AUTH_ITEMBASE_SANDBOX_SECRET = ''
++
++
++- extra scopes can be defined by using::
++
++    SOCIAL_AUTH_ITEMBASE_SCOPE = ['connection.transaction',
++                                  'connection.product',
++                                  'connection.profile',
++                                  'connection.buyer']
++    SOCIAL_AUTH_ITEMBASE_SANDBOX_SCOPE = SOCIAL_AUTH_ITEMBASE_SCOPE
++    
++To use data from the extra scopes, you need to do an extra activation step
++that is not in the usual OAuth flow. For that you can extend your pipeline and
++add a function that sends the user to an activation URL that Itembase provides.
++The method to retrieve the activation data is included in the backend::
++
++    @partial
++    def activation(strategy, backend, response, *args, **kwargs):
++        if backend.name.startswith("itembase"):
++            
++            if strategy.session_pop('itembase_activation_in_progress'):
++                strategy.session_set('itembase_activated', True)
++                
++            if not strategy.session_get('itembase_activated'):
++                activation_data = backend.activation_data(response)
++                strategy.session_set('itembase_activation_in_progress', True)
++                return HttpResponseRedirect(activation_data['activation_url'])
++
++.. _Itembase API: http://developers.itembase.com/authentication/index
+--- /dev/null
++++ b/docs/backends/jawbone.rst
+@@ -0,0 +1,22 @@
++Jawbone
++=======
++
++Jawbone uses OAuth2. In order to enable the backend follow:
++
++- Register an application at `Jawbone Developer Portal`_, set the ``OAuth
++  redirect URIs`` to ``http://<your hostname>/complete/jawbone/``
++
++- Fill in the **Client Id** and **Client Secret** values in your settings::
++
++    SOCIAL_AUTH_JAWBONE_KEY = ''
++    SOCIAL_AUTH_JAWBONE_SECRET = ''
++    
++- Specify scopes with::
++
++    SOCIAL_AUTH_JAWBONE_SCOPE = [...]
++    
++  Available scopes are listed in the `Jawbone Authentication Reference`_,
++  "socpes" section.
++
++.. _Jawbone Developer Portal: https://jawbone.com/up/developer/account/
++.. _Jawbone Authentication Reference: https://jawbone.com/up/developer/authentication
+--- /dev/null
++++ b/docs/backends/justgiving.rst
+@@ -0,0 +1,23 @@
++Just Giving
++===========
++
++OAuth2
++------
++
++Follow the steps at `Just Giving API Docs`_ to register your
++application and get the needed keys.
++
++- Add the Just Giving OAuth2 backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.justgiving.JustGivingOAuth2',
++        ...
++    )
++
++- Fill ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_JUSTGIVING_KEY = ''
++      SOCIAL_AUTH_JUSTGIVING_SECRET = ''
++
++.. _Just Giving API Docs: https://api.justgiving.com/docs
+--- /dev/null
++++ b/docs/backends/kakao.rst
+@@ -0,0 +1,17 @@
++Kakao
++======
++
++Kakao uses OAuth v2 for Authentication.
++
++- Register a new applicationat the `Kakao API`_, and
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_KAKAO_KEY = ''
++      SOCIAL_AUTH_KAKAO_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_KAKAO_SCOPE = [...]
++
++.. _Kakao API: https://developers.kakao.com/docs/restapi
+--- /dev/null
++++ b/docs/backends/khanacademy.rst
+@@ -0,0 +1,25 @@
++Khan Academy
++============
++
++Khan Academy uses a variant of OAuth1 authentication flow. Check the API
++details at `Khan Academy API Authentication`_.
++
++Follow this steps in order to use the backend:
++
++- Register a new application at `Khan Academy API Apps`_,
++
++- Fill **Consumer Key** and **Consumer Secret** values::
++
++    SOCIAL_AUTH_KHANACADEMY_OAUTH1_KEY = ''
++    SOCIAL_AUTH_KHANACADEMY_OAUTH1_SECRET = ''
++
++- Add the backend to ``AUTHENTICATION_BACKENDS`` setting::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.khanacademy.KhanAcademyOAuth1',
++        ...
++    )
++
++.. _Khan Academy API Authentication: https://github.com/Khan/khan-api/wiki/Khan-Academy-API-Authentication
++.. _Khan Academy API Apps: http://www.khanacademy.org/api-apps/register
+--- /dev/null
++++ b/docs/backends/lastfm.rst
+@@ -0,0 +1,17 @@
++Last.fm
++=======
++
++Last.fm uses a similar authentication process than OAuth2 but it's not. In
++order to enable the support for it just:
++
++- Register an application at `Get an API Account`_, set the Last.fm callback to
++  something sensible like http://your.site/complete/lastfm
++
++- Fill in the **API Key** and **API Secret** values in your settings::
++
++    SOCIAL_AUTH_LASTFM_KEY = ''
++    SOCIAL_AUTH_LASTFM_SECRET = ''
++
++- Enable the backend in ``AUTHENTICATION_BACKENDS`` setting.
++    
++.. _Get an API Account: http://www.last.fm/api/account/create
+--- /dev/null
++++ b/docs/backends/launchpad.rst
+@@ -0,0 +1,11 @@
++Launchpad
++=========
++
++`Ubuntu Launchpad <https://launchpad.net/>`_ OpenId doesn't require
++major settings beside being defined on ``AUTHENTICATION_BACKENDS```::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.launchpad.LaunchpadOpenId',
++        ...
++    )
+--- /dev/null
++++ b/docs/backends/line.rst
+@@ -0,0 +1,7 @@
++Line.me
++=======
++
++Fill App Id and Secret in your project settings::
++
++	SOCIAL_AUTH_LINE_KEY = '...'
++	SOCIAL_AUTH_LINE_SECRET = '...'
+--- /dev/null
++++ b/docs/backends/linkedin.rst
+@@ -0,0 +1,68 @@
++LinkedIn
++========
++
++LinkedIn supports OAuth1 and OAuth2. Migration between each type is fair simple
++since the same Key / Secret pair is used for both authentication types.
++
++LinkedIn OAuth setup is similar to any other OAuth service. The auth flow is
++explained on `LinkedIn Developers`_ docs. First you will need to register an
++app att `LinkedIn Developer Network`_.
++
++
++OAuth1
++------
++
++- Fill the application key and secret in your settings::
++
++    SOCIAL_AUTH_LINKEDIN_KEY = ''
++    SOCIAL_AUTH_LINKEDIN_SECRET = ''
++
++- Application scopes can be specified by::
++
++    SOCIAL_AUTH_LINKEDIN_SCOPE = [...]
++
++  Check the available options at `LinkedIn Scopes`_. If you want to request
++  a user's email address, you'll need specify that your application needs
++  access to the email address use the ``r_emailaddress`` scope.
++
++- To request extra fields using `LinkedIn fields selectors`_ just define this
++  setting::
++
++    SOCIAL_AUTH_LINKEDIN_FIELD_SELECTORS = [...]
++
++  with the needed fields selectors, also define ``SOCIAL_AUTH_LINKEDIN_EXTRA_DATA``
++  properly as described in `OAuth <oauth.html>`_, that way the values will be
++  stored in ``UserSocialAuth.extra_data`` field. By default ``id``,
++  ``first-name`` and ``last-name`` are requested and stored.
++
++For example, to request a user's email, headline, and industry from the
++Linkedin API and store the information in ``UserSocialAuth.extra_data``, you
++would add these settings::
++
++    # Add email to requested authorizations.
++    SOCIAL_AUTH_LINKEDIN_SCOPE = ['r_basicprofile', 'r_emailaddress', ...]
++    # Add the fields so they will be requested from linkedin.
++    SOCIAL_AUTH_LINKEDIN_FIELD_SELECTORS = ['email-address', 'headline', 'industry']
++    # Arrange to add the fields to UserSocialAuth.extra_data
++    SOCIAL_AUTH_LINKEDIN_EXTRA_DATA = [('id', 'id'),
++                                       ('firstName', 'first_name'),
++                                       ('lastName', 'last_name'),
++                                       ('emailAddress', 'email_address'),
++                                       ('headline', 'headline'),
++                                       ('industry', 'industry')]
++
++OAuth2
++------
++
++OAuth2 works exacly the same than OAuth1, but the settings must be named as::
++
++    SOCIAL_AUTH_LINKEDIN_OAUTH2_*
++
++Looks like LinkedIn is forcing the definition of the callback URL in the
++application when OAuth2 is used. Be sure to set the proper values, otherwise
++a ``(400) Client Error: Bad Request`` might be returned by their service.
++
++.. _LinkedIn fields selectors: http://developer.linkedin.com/docs/DOC-1014
++.. _LinkedIn Scopes: https://developer.linkedin.com/documents/authentication#granting
++.. _LinkedIn Developer Network: https://www.linkedin.com/secure/developer
++.. _LinkedIn Developers: http://developer.linkedin.com/documents/authentication
+--- /dev/null
++++ b/docs/backends/live.rst
+@@ -0,0 +1,24 @@
++MSN Live Connect
++================
++
++Live uses OAuth2 for its connect workflow, notice that it isn't OAuth WRAP.
++
++- Register a new application at `Live Connect Developer Center`_, set your site
++  domain as redirect domain,
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_LIVE_KEY = ''
++      SOCIAL_AUTH_LIVE_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++     SOCIAL_AUTH_LIVE_SCOPE = [...]
++
++  Defaults are ``wl.basic`` and ``wl.emails``. Latter one is necessary to
++  retrieve user email.
++
++- Ensure to have a valid ``Redirect URL`` (``http://your-domain/complete/live``)
++  defined in the application if ``Enhanced security redirection`` is enabled.
++
++.. _Live Connect Developer Center: https://account.live.com/developers/applications/create
+--- /dev/null
++++ b/docs/backends/livejournal.rst
+@@ -0,0 +1,16 @@
++LiveJournal
++===========
++
++LiveJournal provides OpenId, it doesn't require any major settings in order to
++work, beside being defined on ``AUTHENTICATION_BACKENDS```::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.aol.AOLOpenId',
++        ...
++    )
++
++LiveJournal OpenId is provided by URLs in the form ``http://<username>.livejournal.com``,
++this application retrieves the ``username`` from the data in the current
++request by checking a parameter named ``openid_lj_user`` which can be sent by
++``POST`` or ``GET``.
+--- /dev/null
++++ b/docs/backends/loginradius.rst
+@@ -0,0 +1,48 @@
++LoginRadius
++===========
++
++LoginRadius uses OAuth2 for Authentication with other providers with an HTML
++widget used to trigger the auth process.
++
++- Register a new application at the `LoginRadius Website`_, and
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_LOGINRADIUS_KEY = ''
++      SOCIAL_AUTH_LOGINRADIUS_SECRET = ''
++
++- Since the auth process is triggered by LoginRadius JS script, you need to
++  sever such content to the user, all you need to do that is a template with
++  the following content::
++
++    <div id="interfacecontainerdiv" class="interfacecontainerdiv"></div>
++    <script src="https://hub.loginradius.com/include/js/LoginRadius.js"></script>
++    <script type="text/javascript">
++        var options = {};
++        options.login = true;
++        LoginRadius_SocialLogin.util.ready(function () {
++            $ui = LoginRadius_SocialLogin.lr_login_settings;
++            $ui.interfacesize = "";
++            $ui.apikey = "{{ LOGINRADIUS_KEY }}";
++            $ui.callback = "{{ LOGINRADIUS_REDIRECT_URL }}";
++            $ui.lrinterfacecontainer = "interfacecontainerdiv";
++            LoginRadius_SocialLogin.init(options);
++        });
++    </script>
++
++  Put that content in a template named ``loginradius.html`` (accessible to your
++  framework), or define a name with ``SOCIAL_AUTH_LOGINRADIUS_TEMPLATE`` setting,
++  like::
++
++    SOCIAL_AUTH_LOGINRADIUS_LOCAL_HTML = 'loginradius.html'
++
++  The template context will have the current backend instance under the
++  ``backend`` name, also the application key (``LOGINRADIUS_KEY``) and the
++  redirect URL (``LOGINRADIUS_REDIRECT_URL``).
++
++- Further documentation can be found at `LoginRadius API Documentation`_ and
++  `LoginRadius Datapoints`_
++
++.. _LoginRadius Website: https://loginradius.com/
++.. _LoginRadius API Documentation: http://api.loginradius.com/help/
++.. _LoginRadius Datapoints: http://www.loginradius.com/datapoints/
+--- /dev/null
++++ b/docs/backends/mailru.rst
+@@ -0,0 +1,7 @@
++Mail.ru OAuth
++=============
++
++Mail.ru uses OAuth2 workflow, to use it fill in settings::
++
++    SOCIAL_AUTH_MAILRU_OAUTH2_KEY = ''
++    SOCIAL_AUTH_MAILRU_OAUTH2_SECRET = ''
+--- /dev/null
++++ b/docs/backends/mapmyfitness.rst
+@@ -0,0 +1,13 @@
++MapMyFitness
++============
++
++MapMyFitness uses OAuth v2 for authentication.
++
++- Register a new application at the `MapMyFitness API`_, and
++
++- fill ``key`` and ``secret`` values in the settings::
++
++      SOCIAL_AUTH_MAPMYFITNESS_KEY = ''
++      SOCIAL_AUTH_MAPMYFITNESS_SECRET = ''
++
++.. _MapMyFitness API: https://www.mapmyapi.com
+--- /dev/null
++++ b/docs/backends/meetup.rst
+@@ -0,0 +1,14 @@
++Meetup
++======
++
++Meetup.com uses OAuth2 for its auth mechanism.
++
++- Register a new OAuth Consumer at `Meetup Consumer Registration`_, set your
++  consumer name, redirect uri.
++
++- Fill ``key`` and ``secret`` values in the settings::
++
++      SOCIAL_AUTH_MEETUP_KEY = ''
++      SOCIAL_AUTH_MEETUP_SECRET = ''
++
++.. _Meetup Consumer Registration: https://secure.meetup.com/meetup_api/oauth_consumers/create
+--- /dev/null
++++ b/docs/backends/mendeley.rst
+@@ -0,0 +1,38 @@
++Mendeley
++========
++
++Mendeley supports OAuth1 and OAuth2, they are in the process of deprecating
++OAuth1 API (which should be fully deprecated on April 2014, check their
++announcement_).
++
++
++OAuth1
++------
++
++In order to support OAuth1 (not recomended, use OAuth2 instead):
++
++- Register a new application at `Mendeley Application Registration`_
++
++- Fill **Consumer Key** and **Consumer Secret** values::
++
++      SOCIAL_AUTH_MENDELEY_KEY = ''
++      SOCIAL_AUTH_MENDELEY_SECRET = ''
++
++
++OAuth2
++------
++
++In order to support OAuth2:
++
++- Register a new application at `Mendeley Application Registration`_, or
++  migrate your OAuth1 application, check their `migration steps here`_.
++
++- Fill **Application ID** and **Application Secret** values::
++
++      SOCIAL_AUTH_MENDELEY_OAUTH2_KEY = ''
++      SOCIAL_AUTH_MENDELEY_OAUTH2_SECRET = ''
++
++
++.. _Mendeley Application Registration: http://dev.mendeley.com/applications/register/
++.. _announcement: https://sites.google.com/site/mendeleyapi/home/authentication
++.. _migration steps here: https://groups.google.com/forum/#!topic/mendeley-open-api-developers/KmUQW9I0ST0
+--- /dev/null
++++ b/docs/backends/mineid.rst
+@@ -0,0 +1,25 @@
++MineID
++======
++
++MineID works similar to Facebook (OAuth).
++
++- Register a new application at `MineID.org`_, set the callback URL to
++  ``http://example.com/complete/mineid/`` replacing ``example.com`` with your
++  domain.
++
++- Fill ``Client ID`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_MINEID_KEY = ''
++      SOCIAL_AUTH_MINEID_SECRET = ''
++
++
++Self-hosted MineID
++------------------
++
++Since MineID is an Open Source software and can be self-hosted, you can
++change settings to point to your instance::
++
++    SOCIAL_AUTH_MINEID_HOST = 'www.your-mineid-instance.com'
++    SOCIAL_AUTH_MINEID_SCHEME = 'https'  # or 'http'
++
++.. _MineID.org: https://www.mineid.org/
+--- /dev/null
++++ b/docs/backends/mixcloud.rst
+@@ -0,0 +1,31 @@
++Mixcloud OAuth2
++===============
++
++The `Mixcloud API`_ offers support for authorization. To this backend support:
++
++- Register a new application at `Mixcloud Developers`_
++
++- Add Mixcloud backend to ``AUTHENTICATION_BACKENDS`` in settings::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.mixcloud.MixcloudOAuth2',
++    )
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++    SOCIAL_AUTH_MIXCLOUD_KEY = ''
++    SOCIAL_AUTH_MIXCLOUD_SECRET = ''
++
++- Similar to the other OAuth backends you can define::
++
++    SOCIAL_AUTH_MIXCLOUD_EXTRA_DATA = [('username', 'username'),
++                                       ('name', 'name'),
++                                       ('pictures', 'pictures'),
++                                       ('url', 'url')]
++
++  as a list of tuples ``(response name, alias)`` to store user profile data on
++  the ``UserSocialAuth.extra_data``.
++
++.. _Mixcloud API: http://www.mixcloud.com/developers/documentation
++.. _Mixcloud Developers: http://www.mixcloud.com/developers
+--- /dev/null
++++ b/docs/backends/moves.rst
+@@ -0,0 +1,31 @@
++Moves
++=====
++
++Moves_ provides an OAuth2 authentication flow. In order to enable it:
++
++- Register an application at `Manage Your Apps`_, remember to fill the
++  ``Redirect URI`` once the application was created.
++
++- Fill **Client ID** and **Client secret** in the settings::
++
++    SOCIAL_AUTH_MOVES_KEY = ''
++    SOCIAL_AUTH_MOVES_SECRET = ''
++
++- Define the mandatory scope for your application::
++
++    SOCIAL_AUTH_MOVES_SCOPE = ['activity', 'location']
++
++  The scope parameter is required by Moves_ but the backend doesn't set
++  a default one to minimize the application permissions request, so it's
++  mandatory for the developer to define this setting.
++
++- Add the backend to the ``AUTHENTICATION_BACKENDS`` setting::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.moves.MovesOAuth2',
++        ...
++    )
++
++.. _Moves: http://moves-app.com/
++.. _Manage Your Apps: https://dev.moves-app.com/apps
+--- /dev/null
++++ b/docs/backends/naszaklasa.rst
+@@ -0,0 +1,26 @@
++NationBuilder
++=============
++
++`NaszaKlasa supports OAuth2`_ as their authentication mechanism. Follow these
++steps in order to use it:
++
++- Register a new application at your `NK Developers`_ (define the `Callback
++  URL` to ``http://example.com/complete/nk/`` where ``example.com``
++  is your domain).
++
++- Fill the ``Client ID`` and ``Client Secret`` values from the newly created
++  application::
++
++    SOCIAL_AUTH_NK_KEY = ''
++    SOCIAL_AUTH_NK_SECRET = ''
++
++- Enable the backend in ``AUTHENTICATION_BACKENDS`` setting::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.nk.NKOAuth2',
++        ...
++    )
++
++.. _NaszaKlasa supports OAuth2: https://developers.nk.pl
++.. _NK Developers: https://developers.nk.pl/developers/oauth2client/form
+\ No newline at end of file
+--- /dev/null
++++ b/docs/backends/nationbuilder.rst
+@@ -0,0 +1,30 @@
++NationBuilder
++=============
++
++`NationBuilder supports OAuth2`_ as their authentication mechanism. Follow these
++steps in order to use it:
++
++- Register a new application at your `Nation Admin panel`_ (define the `Callback
++  URL` to ``http://example.com/complete/nationbuilder/`` where ``example.com``
++  is your domain).
++
++- Fill the ``Client ID`` and ``Client Secret`` values from the newly created
++  application::
++
++    SOCIAL_AUTH_NATIONBUILDER_KEY = ''
++    SOCIAL_AUTH_NATIONBUILDER_SECRET = ''
++
++- Also define your NationBuilder slug::
++
++    SOCIAL_AUTH_NATIONBUILDER_SLUG = 'your-nationbuilder-slug'
++
++- Enable the backend in ``AUTHENTICATION_BACKENDS`` setting::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.nationbuilder.NationBuilderOAuth2'
++        ...
++    )
++
++.. _Nation Admin panel: https://psa.nationbuilder.com/admin/apps
++.. _NationBuilder supports OAuth2: http://nationbuilder.com/api_quickstart
+--- /dev/null
++++ b/docs/backends/naver.rst
+@@ -0,0 +1,27 @@
++Naver
++=====
++
++Naver uses OAuth v2 for Authentication.
++
++- Register a new application at the `Naver API`_, and
++
++- add naver oauth backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.naver.NaverOAuth2',
++        ...
++    )
++
++- fill ``Client ID`` and ``Client Secret`` from developer.naver.com
++  values in the settings::
++
++	SOCIAL_AUTH_NAVER_KEY = ''
++	SOCIAL_AUTH_NAVER_SECRET = ''
++
++- you can get EXTRA_DATA::
++
++	SOCIAL_AUTH_NAVER_EXTRA_DATA = ['nickname', 'gender', 'age',
++                                        'birthday', 'profile_image']
++
++.. _Naver API: https://nid.naver.com/devcenter/docs.nhn?menu=API
+--- /dev/null
++++ b/docs/backends/ngpvan_actionid.rst
+@@ -0,0 +1,36 @@
++NGP VAN ActionID
++================
++
++`NGP VAN`_'s ActionID_ service provides an OpenID 1.1 endpoint, which provides
++first name, last name, email address, and phone number.
++
++ActionID doesn't require major settings beside being defined on
++``AUTHENTICATION_BACKENDS``
++
++.. code-block:: python
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.ngpvan.ActionIDOpenID',
++        ...
++    )
++
++
++If you want to be able to access the "phone" attribute offered by NGP VAN
++within ``extra_data`` you can add the following to your settings:
++
++.. code-block:: python
++
++    SOCIAL_AUTH_ACTIONID_OPENID_AX_EXTRA_DATA = [
++        ('http://openid.net/schema/contact/phone/business', 'phone')
++    ]
++
++
++NGP VAN offers the ability to have your domain whitelisted, which will disable
++the "{domain} is requesting a link to your ActionID" warning when your app
++attempts to login using an ActionID account. Contact
++`NGP VAN Developer Support`_ for more information
++
++.. _NGP VAN: http://www.ngpvan.com/
++.. _ActionID: http://developers.ngpvan.com/action-id
++.. _NGP VAN Developer Support: http://developers.ngpvan.com/support/contact
+--- /dev/null
++++ b/docs/backends/oauth.rst
+@@ -0,0 +1,31 @@
++OAuth
++=====
++
++OAuth_ communication demands a set of keys exchange to validate the client
++authenticity prior to user approbation. Twitter, and Facebook facilitates
++these keys by application registration, Google works the same,
++but provides the option for unregistered applications.
++
++Check next sections for details.
++
++OAuth_ backends also can store extra data in ``UserSocialAuth.extra_data``
++field by defining a set of values names to retrieve from service response.
++
++Settings is per backend and its name is dynamically checked using uppercase
++backend name as prefix::
++
++    SOCIAL_AUTH_<uppercase backend name>_EXTRA_DATA
++
++Example::
++
++    SOCIAL_AUTH_FACEBOOK_EXTRA_DATA = [(..., ...)]
++
++Settings must be a list of tuples mapping value name in response and value
++alias used to store. A third value (boolean) is supported, its purpose is
++to signal if the value should be discarded if it evaluates to ``False``, this
++is to avoid replacing old (needed) values when they don't form part of current
++response. If not present, then this check is avoided and the value will replace
++any data.
++
++
++.. _OAuth: http://oauth.net/
+--- /dev/null
++++ b/docs/backends/odnoklassnikiru.rst
+@@ -0,0 +1,56 @@
++Odnoklassniki.ru
++================
++
++There are two options with Odnoklassniki: either you use OAuth2 workflow to
++authenticate odnoklassniki users at external site, or you authenticate users
++within your IFrame application.
++
++OAuth2
++------
++
++If you use OAuth2 workflow, you need to:
++
++- register a new application with `OAuth registration form`_
++
++- fill out some settings::
++
++    SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_KEY = ''
++    SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_SECRET = ''
++    SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_PUBLIC_NAME = ''
++
++- add ``'social.backends.odnoklassniki.OdnoklassnikiOAuth2'`` into your
++  ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``.
++
++
++IFrame applications
++-------------------
++
++If you want to authenticate users in your IFrame application,
++
++- read `Rules for application developers`_
++
++- fill out `Developers registration form`_
++
++- get your personal sandbox
++
++- fill out some settings::
++
++    SOCIAL_AUTH_ODNOKLASSNIKI_APP_KEY = ''
++    SOCIAL_AUTH_ODNOKLASSNIKI_APP_SECRET = ''
++    SOCIAL_AUTH_ODNOKLASSNIKI_APP_PUBLIC_NAME = ''
++
++- add ``'social.backends.odnoklassniki.OdnoklassnikiApp'`` into your
++  ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``
++
++- sign a public offer and do some bureaucracy
++
++You may also use::
++
++    SOCIAL_AUTH_ODNOKLASSNIKI_APP_EXTRA_USER_DATA_LIST
++
++Defaults to empty tuple, for the list of available fields see `Documentation on user.getInfo`_
++
++.. _OAuth registration form: https://apiok.ru/wiki/pages/viewpage.action?pageId=42476652
++.. _Rules for application developers: https://apiok.ru/wiki/display/ok/Odnoklassniki.ru+Third+Party+Platform
++.. _Developers registration form: https://apiok.ru/wiki/pages/viewpage.action?pageId=5668937
++.. _Documentation on user.getInfo: https://apiok.ru/wiki/display/ok/REST+API+-+users.getInfo
+--- /dev/null
++++ b/docs/backends/openid.rst
+@@ -0,0 +1,46 @@
++OpenId
++======
++
++OpenId_ support is simpler to implement than OAuth_. Google and Yahoo
++providers are supported by default, others are supported by POST method
++providing endpoint URL.
++
++OpenId_ backends can store extra data in ``UserSocialAuth.extra_data`` field
++by defining a set of values names to retrieve from any of the used schemas,
++AttributeExchange and SimpleRegistration. As their keywords differ we need
++two settings.
++
++Settings is per backend, so we have two possible values for each one. Name
++is dynamically checked using uppercase backend name as prefix::
++
++    SOCIAL_AUTH_<uppercase backend name>_SREG_EXTRA_DATA
++    SOCIAL_AUTH_<uppercase backend name>_AX_EXTRA_DATA
++
++Example::
++
++    SOCIAL_AUTH_GOOGLE_SREG_EXTRA_DATA = [(..., ...)]
++    SOCIAL_AUTH_GOOGLE_AX_EXTRA_DATA = [(..., ...)]
++
++Settings must be a list of tuples mapping value name in response and value
++alias used to store. A third value (boolean) is supported to, it's purpose is
++to signal if the value should be discarded if it evaluates to ``False``, this
++is to avoid replacing old (needed) values when they don't form part of current
++response. If not present, then this check is avoided and the value will replace
++any data.
++
++Username
++--------
++
++The OpenId_ backend will check for a ``username`` key in the values returned by
++the server, but default to ``first-name`` + ``last-name`` if that key is
++missing. It's possible to indicate the username key in the values If the
++username is under a different key with a setting, but backends should have
++defined a default value. For example::
++
++    SOCIAL_AUTH_FEDORA_USERNAME_KEY = 'nickname'
++
++This setting indicates that the username should be populated by the
++``nickname`` value in the Fedora OpenId_ provider.
++
++.. _OpenId: http://openid.net/
++.. _OAuth: http://oauth.net/
+--- /dev/null
++++ b/docs/backends/openstreetmap.rst
+@@ -0,0 +1,21 @@
++OpenStreetMap
++=============
++
++OpenStreetMap supports OAuth 1.0 and 1.0a but 1.0a should be used for the new
++applications, as 1.0 is for support of legacy clients only.
++
++Access tokens currently do not expire automatically.
++
++More documentation at `OpenStreetMap Wiki`_:
++
++- Login to your account
++
++- Register your application as OAuth consumer on your `OpenStreetMap user settings page`_, and
++
++- Set ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_OPENSTREETMAP_KEY = ''
++      SOCIAL_AUTH_OPENSTREETMAP_SECRET = ''
++
++.. _OpenStreetMap Wiki: http://wiki.openstreetmap.org/wiki/OAuth
++.. _OpenStreetMap user settings page: http://www.openstreetmap.org/user/username/oauth_clients/new
+--- /dev/null
++++ b/docs/backends/orbi.rst
+@@ -0,0 +1,17 @@
++Orbi
++====
++
++Orbi OAuth v2 for Authentication.
++
++- Register a new applicationat the `Orbi API`_, and
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_ORBI_KEY = ''
++      SOCIAL_AUTH_ORBI_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_KAKAO_SCOPE = ['all']
++
++.. _Orbi API: http://orbi.kr
+--- /dev/null
++++ b/docs/backends/persona.rst
+@@ -0,0 +1,43 @@
++Mozilla Persona
++===============
++
++Support for `Mozilla Persona`_ is possible by posting the ``assertion`` code to
++``/complete/persona/`` URL.
++
++The setup doesn't need any setting, just the usual `Mozilla Persona`_
++javascript include in your document and the needed mechanism to trigger the
++POST to `python-social-auth`_::
++
++    <!-- Include BrowserID JavaScript -->
++    <script src="https://login.persona.org/include.js" type="text/javascript"></script>
++
++    <!-- Define a form to send the POST data -->
++    <form method="post" action="/complete/persona/">
++        <input type="hidden" name="assertion" value="" />
++        <a rel="nofollow" id="persona" href="#">Mozilla Persona</a>
++    </form>
++
++    <!-- Setup click handler that retieves Persona assertion code and sends POST data -->
++    <script type="text/javascript">
++        $(function () {
++            $('#persona').click(function (e) {
++                e.preventDefault();
++                var self = $(this);
++
++                navigator.id.get(function (assertion) {
++                    if (assertion) {
++                        self.parent('form')
++                                .find('input[type=hidden]')
++                                    .attr('value', assertion)
++                                    .end()
++                                .submit();
++                    } else {
++                        alert('Some error occurred');
++                    }
++                });
++            });
++        });
++    </script>
++
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _Mozilla Persona: http://www.mozilla.org/persona/
+--- /dev/null
++++ b/docs/backends/pinterest.rst
+@@ -0,0 +1,29 @@
++Pinterest
++=========
++
++Pinterest implemented OAuth2 protocol for their authentication mechanism.
++To enable ``python-social-auth`` support follow this steps:
++
++1. Go to `Pinterest developers zone`_ and create an application.
++
++2. Fill App Id and Secret in your project settings::
++
++    SOCIAL_AUTH_PINTEREST_KEY = '...'
++    SOCIAL_AUTH_PINTEREST_SECRET = '...'
++    SOCIAL_AUTH_PINTEREST_SCOPE = [
++        'read_public',
++        'write_public',
++        'read_relationships',
++        'write_relationships'
++    ]
++
++3. Enable the backend::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.pinterest.PinterestOAuth2',
++        ...
++    )
++
++.. _Pinterest developers zone: https://developers.pinterest.com/apps/
++.. _Pinterest Documentation: https://developers.pinterest.com/docs/
+--- /dev/null
++++ b/docs/backends/pixelpin.rst
+@@ -0,0 +1,33 @@
++PixelPin
++========
++
++PixelPin only supports OAuth2.
++
++PixelPin OAuth2
++---------------
++
++Developer documentation for PixelPin can be found at
++http://developer.pixelpin.co.uk/. To setup OAuth2 do the following:
++
++- Register a new developer account at `PixelPin Developers`_.
++
++  You require a PixelPin account to create developer accounts. Sign up at
++  `PixelPin Account Page`_ For the value of redirect uri, use whatever path you
++  need to return to on your web application. The example code provided with the
++  plugin uses ``http://<yoursite>/complete/pixelpin-oauth2/``.
++
++  Once verified by email, record the values of client id and secret for the
++  next step.
++
++- Fill **Consumer Key** and **Consumer Secret** values in your settings.py
++  file::
++
++      SOCIAL_AUTH_PIXELPIN_OAUTH2_KEY = ''
++      SOCIAL_AUTH_PIXELPIN_OAUTH2_SECRET = ''
++
++- Add ``'social.backends.pixelpin.PixelPinOAuth2'`` into your
++  ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``.
++
++.. _PixelPin homepage: http://pixelpin.co.uk/
++.. _PixelPin Account Page: https://login.pixelpin.co.uk/
++.. _PixelPin Developers: http://developer.pixelpin.co.uk/
+--- /dev/null
++++ b/docs/backends/pocket.rst
+@@ -0,0 +1,12 @@
++Pocket
++======
++
++Pocket uses a weird variant of OAuth v2 that only defines a consumer key.
++
++- Register a new application at the `Pocket API`_, and
++
++- fill ``consumer key`` value in the settings::
++
++      SOCIAL_AUTH_POCKET_KEY = ''
++
++.. _Pocket API: http://getpocket.com/developer/
+--- /dev/null
++++ b/docs/backends/podio.rst
+@@ -0,0 +1,13 @@
++Podio
++=====
++
++Podio offers OAuth2 as their auth mechanism. In order to enable it, follow:
++
++- Register a new application at `Podio API Keys`_
++
++- Fill **Client Id** and **Client Secret** values::
++
++      SOCIAL_AUTH_PODIO_KEY = ''
++      SOCIAL_AUTH_PODIO_SECRET = ''
++
++.. _Podio API Keys: https://developers.podio.com/api-key
+--- /dev/null
++++ b/docs/backends/qiita.rst
+@@ -0,0 +1,23 @@
++Qiita
++=====
++
++Qiita
++
++- Register a new application at Qiita_, set the callback URL to
++  ``http://example.com/complete/qiita/`` replacing ``example.com`` with your
++  domain.
++
++- Fill ``Client ID`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_QIITA_KEY = ''
++      SOCIAL_AUTH_QIITA_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_QIITA_SCOPE = [...]
++
++  See auth scopes at `Qiita Scopes docs`_.
++
++
++.. _Qiita: https://qiita.com/settings/applications
++.. _Qiita Scopes docs: https://qiita.com/api/v2/docs#スコープ
+--- /dev/null
++++ b/docs/backends/qq.rst
+@@ -0,0 +1,32 @@
++QQ
++==
++
++QQ implemented OAuth2 protocol for their authentication mechanism. To enable
++``python-social-auth`` support follow this steps:
++
++1. Go to `QQ`_ and create an application.
++
++2. Fill App Id and Secret in your project settings::
++
++    SOCIAL_AUTH_QQ_KEY = '...'
++    SOCIAL_AUTH_QQ_SECRET = '...'
++
++3. Enable the backend::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.qq.QQOauth2',
++        ...
++    )
++
++
++The values for ``nickname``, ``figureurl_qq_1`` and ``gender`` will be stored
++in the ``extra_data`` field. The ``nickname`` will be used as the account
++username. ``figureurl_qq_1`` can be used as the profile image.
++
++Sometimes nickname will duplicate with another ``qq`` account, to avoid this
++issue it's possible to use ``openid`` as ``username`` by define this setting::
++
++    SOCIAL_AUTH_QQ_USE_OPENID_AS_USERNAME = True
++
++.. _QQ: http://connect.qq.com/
+--- /dev/null
++++ b/docs/backends/rdio.rst
+@@ -0,0 +1,46 @@
++Rdio
++====
++
++Rdio provides OAuth 1 and 2 support for their authentication process.
++
++OAuth 1.0a
++----------
++
++To setup Rdio OAuth 1.0a, add the following to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.rdio.RdioOAuth1',
++        ...
++    )
++
++    SOCIAL_AUTH_RDIO_OAUTH1_KEY = ''
++    SOCIAL_AUTH_RDIO_OAUTH1_SECRET = ''
++
++
++OAuth 2.0
++---------
++
++To setup Rdio OAuth 2.0, add the following to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.rdio.RdioOAuth2',
++        ...
++    )
++
++    SOCIAL_AUTH_RDIO_OAUTH2_KEY = os.environ['RDIO_OAUTH2_KEY']
++    SOCIAL_AUTH_RDIO_OAUTH2_SECRET = os.environ['RDIO_OAUTH2_SECRET']
++    SOCIAL_AUTH_RDIO_OAUTH2_SCOPE = []
++
++
++Extra Fields
++------------
++
++The following extra fields are automatically requested:
++
++- rdio_id
++- rdio_icon_url
++- rdio_profile_url
++- rdio_username
++- rdio_stream_region
+--- /dev/null
++++ b/docs/backends/readability.rst
+@@ -0,0 +1,24 @@
++Readability
++===========
++
++Readability works similarly to Twitter, in that you'll need a ``Consumer Key``
++and ``Consumer Secret``.  These can be obtained in the ``Connections`` section
++of your ``Account`` page.
++
++- Fill the **Consumer Key** and **Consumer Secret** values in your settings::
++
++    SOCIAL_AUTH_READABILITY_KEY = ''
++    SOCIAL_AUTH_READABILITY_SECRET = ''
++
++That's it! By default you'll get back::
++
++    username
++    first_name
++    last_name
++
++with EXTRA_DATA, you can get::
++    
++    date_joined
++    kindle_email_address
++    avatar_url
++    email_into_address
+--- /dev/null
++++ b/docs/backends/reddit.rst
+@@ -0,0 +1,33 @@
++Reddit
++======
++
++Reddit implements `OAuth2 authentication workflow`_. To enable it, just follow:
++
++- Register an application at `Reddit Preferences Apps`_
++
++- Fill the **Consumer Key** and **Consumer Secret** values in your settings::
++
++    SOCIAL_AUTH_REDDIT_KEY = ''
++    SOCIAL_AUTH_REDDIT_SECRET = ''
++
++- By default the token is not permanent, it will last an hour. To get
++  a refresh token just define::
++
++    SOCIAL_AUTH_REDDIT_AUTH_EXTRA_ARGUMENTS = {'duration': 'permanent'}
++
++  This will store the ``refresh_token`` in ``UserSocialAuth.extra_data``
++  attribute, to refresh the access token just do::
++
++    from social.apps.django_app.utils import load_strategy
++
++    strategy = load_strategy(backend='reddit')
++    user = User.objects.get(pk=foo)
++    social = user.social_auth.filter(provider='reddit')[0]
++    social.refresh_token(strategy=strategy,
++                         redirect_uri='http://localhost:8000/complete/reddit/')
++
++  Reddit requires ``redirect_uri`` when refreshing the token and it must be the
++  same value used during the auth process.
++
++.. _Reddit Preferences Apps: https://ssl.reddit.com/prefs/apps/
++.. _OAuth2 authentication workflow: https://github.com/reddit/reddit/wiki/OAuth2
+--- /dev/null
++++ b/docs/backends/runkeeper.rst
+@@ -0,0 +1,13 @@
++RunKeeper
++=========
++
++RunKeeper uses OAuth v2 for authentication.
++
++- Register a new application at the `RunKeeper API`_, and
++
++- fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_RUNKEEPER_KEY = ''
++      SOCIAL_AUTH_RUNKEEPER_SECRET = ''
++
++.. _RunKeeper API: http://developer.runkeeper.com/healthgraph
+--- /dev/null
++++ b/docs/backends/salesforce.rst
+@@ -0,0 +1,44 @@
++Salesforce
++==========
++
++Salesforce uses OAuth v2 for Authentication, check the `official docs`_.
++
++- Create an app following the steps in the `Defining Connected Apps`_ docs.
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++        SOCIAL_AUTH_SALESFORCE_OAUTH2_KEY = '<App UID>'
++        SOCIAL_AUTH_SALESFORCE_OAUTH2_SECRET = '<App secret>'
++
++- Add the backend to the ``AUTHENTICATION_BACKENDS`` setting::
++
++        AUTHENTICATION_BACKENDS = (
++            ...
++            'social.backends.salesforce.SalesforceOAuth2',
++            ...
++        )
++
++- Then you can start using ``{% url social:begin 'salesforce-oauth2' %}`` in
++  your templates
++
++
++If using the sandbox mode:
++
++- Fill these settings instead::
++
++        SOCIAL_AUTH_SALESFORCE_OAUTH2_SANDBOX_KEY = '<App UID>'
++        SOCIAL_AUTH_SALESFORCE_OAUTH2_SANDBOX_SECRET = '<App secret>'
++
++- And this backend::
++
++        AUTHENTICATION_BACKENDS = (
++            ...
++            'social.backends.salesforce.SalesforceOAuth2Sandbox',
++            ...
++        )
++
++- Then you can start using ``{% url social:begin 'salesforce-oauth2-sandbox' %}``
++  in your templates
++
++.. _official docs: https://www.salesforce.com/us/developer/docs/api_rest/Content/intro_understanding_web_server_oauth_flow.htm
++.. _Defining Connected Apps: https://www.salesforce.com/us/developer/docs/api_rest/Content/intro_defining_remote_access_applications.htm
+--- /dev/null
++++ b/docs/backends/saml.rst
+@@ -0,0 +1,169 @@
++SAML
++====
++
++The SAML backend allows users to authenticate with any provider that supports
++the SAML 2.0 protocol (commonly used for corporate or academic single sign on).
++
++The SAML backend for python-social-auth allows your web app to act as a SAML
++Service Provider. You can configure one or more SAML Identity Providers that
++users can use for authentication. For example, if your users are students, you
++could enable Harvard and MIT as identity providers, so that students of either
++of those two universities can use their campus login to access your app.
++
++Required Dependency
++-------------------
++
++You must install python-saml_ 2.1.3 or higher in order to use this backend.
++
++Required Configuration
++----------------------
++
++At a minimum, you must add the following to your project's settings:
++
++- ``SOCIAL_AUTH_SAML_SP_ENTITY_ID``: The SAML Entity ID for your app. This
++  should be a URL that includes a domain name you own. It doesn't matter what
++  the URL points to. Example: ``http://saml.yoursite.com``
++
++- ``SOCIAL_AUTH_SAML_SP_PUBLIC_CERT``: The X.509 certificate string for the
++  key pair that your app will use. You can generate a new self-signed key pair
++  with::
++
++      openssl req -new -x509 -days 3652 -nodes -out saml.crt -keyout saml.key
++
++  The contents of ``saml.crt`` should then be used as the value of this setting
++  (you can omit the first and last lines, which aren't required).
++
++- ``SOCIAL_AUTH_SAML_SP_PRIVATE_KEY``: The private key to be used by your app.
++  If you used the example openssl command given above, set this to the contents
++  of ``saml.key`` (again, you can omit the first and last lines).
++
++- ``SOCIAL_AUTH_SAML_ORG_INFO``: A dictionary that contains information about
++  your app. You must specify values for English at a minimum. Each language's
++  entry should specify a ``name`` (not shown to the user), a ``displayname``
++  (shown to the user), and a URL. See the following
++  example::
++
++      {
++          "en-US": {
++              "name": "example",
++              "displayname": "Example Inc.",
++              "url": "http://example.com",
++          }
++      }
++
++- ``SOCIAL_AUTH_SAML_TECHNICAL_CONTACT``: A dictionary with two values,
++  ``givenName`` and ``emailAddress``, describing the name and email of a
++  technical contact responsible for your app. Example::
++
++      {"givenName": "Tech Gal", "emailAddress": "technical at example.com"}
++
++- ``SOCIAL_AUTH_SAML_TECHNICAL_CONTACT``: A dictionary with two values,
++  ``givenName`` and ``emailAddress``, describing the name and email of a
++  support contact for your app. Example::
++
++      SOCIAL_AUTH_SAML_SUPPORT_CONTACT = {
++          "givenName": "Support Guy",
++          "emailAddress": "support at example.com",
++      }
++
++- ``SOCIAL_AUTH_SAML_ENABLED_IDPS``: The most important setting. List the Entity
++  ID, SSO URL, and x.509 public key certificate for each provider that your app
++  wants to support. The SSO URL must support the ``HTTP-Redirect`` binding.
++  You can get these values from the provider's XML metadata. Here's an example,
++  for TestShib_ (the values come from TestShib's metadata_)::
++
++      {
++          "testshib": {
++              "entity_id": "https://idp.testshib.org/idp/shibboleth",
++              "url": "https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO",
++              "x509cert": "MIIEDjCCAvagAwIBAgIBADA ... 8Bbnl+ev0peYzxFyF5sQA==",
++          }
++      }
++
++Basic Usage
++-----------
++
++- Set all of the required configuration variables described above.
++
++- Generate the SAML XML metadata for your app. The best way to do this is to
++  create a new view/page/URL in your app that will call the backend's
++  ``generate_metadata_xml()`` method. Here's an example of how to do this in
++  Django::
++
++      def saml_metadata_view(request):
++          complete_url = reverse('social:complete', args=("saml", ))
++          saml_backend = load_backend(
++              load_strategy(request),
++              "saml",
++              redirect_uri=complete_url,
++          )
++          metadata, errors = saml_backend.generate_metadata_xml()
++          if not errors:
++              return HttpResponse(content=metadata, content_type='text/xml')
++
++- Download the metadata for your app that was generated by the above method,
++  and send it to each Identity Provider (IdP) that you wish to use. Each IdP
++  must install and configure your metadata on their system before it will work.
++
++- Now everything is set! To allow users to login with any given IdP, you need to
++  give them a link to the python-social-auth "begin"/"auth" URL and include an
++  ``idp`` query parameter that specifies the name of the IdP to use. This is
++  needed since the backend supports multiple IdPs. The names of the IdPs are the
++  keys used in the ``SOCIAL_AUTH_SAML_ENABLED_IDPS`` setting.
++
++  Django example::
++
++      # In view:
++      context['testshib_url'] = u"{base}?{params}".format(
++          base=reverse('social:begin', kwargs={'backend': 'saml'}),
++          params=urllib.urlencode({'next': '/home', 'idp': 'testshib'})
++      )
++      # In template:
++      <a href="{{ testshib_url }}">TestShib Login</a>
++      # Result:
++      <a href="/login/saml/?next=%2Fhome&idp=testshib">TestShib Login</a>
++
++- Testing with the TestShib_ provider is recommended, as it is known to work
++  well.
++
++
++Advanced Settings
++-----------------
++
++- ``SOCIAL_AUTH_SAML_SP_EXTRA``: This can be set to a dict, and any key/value
++  pairs specified here will be passed to the underlying ``python-saml`` library
++  configuration's ``sp`` setting. Refer to the ``python-saml`` documentation for
++  details.
++
++- ``SOCIAL_AUTH_SAML_SECURITY_CONFIG``: This can be set to a dict, and any
++  key/value pairs specified here will be passed to the underlying
++  ``python-saml`` library configuration's ``security`` setting. Two useful keys
++  that you can set are ``metadataCacheDuration`` and ``metadataValidUntil``,
++  which control the expiry time of your XML metadata. By default, a cache
++  duration of 10 days will be used, which means that IdPs are allowed to cache
++  your metadata for up to 10 days, but no longer. ``metadataCacheDuration`` must
++  be specified as an ISO 8601 duration string (e.g. `P1D` for one day).
++
++
++Advanced Usage
++--------------
++
++You can subclass the ``SAMLAuth`` backend to provide custom functionality. In
++particular, there are two methods that are designed for subclasses to override:
++
++- ``get_idp(self, idp_name)``: Given the name of an IdP, return an instance of
++  ``SAMLIdentityProvider`` with the details of the IdP. Override this method if
++  you wish to use some other method for configuring the available identity
++  providers, such as fetching them at runtime from another server, or using a
++  list of providers from a Shibboleth federation.
++
++- ``_check_entitlements(self, idp, attributes)``: This method gets called during
++  the login process and is where you can decide to accept or reject a user based
++  on the user's SAML attributes. For example, you can restrict access to your
++  application to only accept users who belong to a certain department. After
++  inspecting the passed attributes parameter, do nothing to allow the user to
++  login, or raise ``social.exceptions.AuthForbidden`` to reject the user.
++
++.. _python-saml: https://github.com/onelogin/python-saml
++.. _TestShib: https://www.testshib.org/
++.. _metadata: https://www.testshib.org/metadata/testshib-providers.xml
+--- /dev/null
++++ b/docs/backends/shopify.rst
+@@ -0,0 +1,29 @@
++Shopify
++=======
++
++Shopify uses OAuth 2 for authentication.
++
++To use this backend, you must install the package ``shopify`` from the `Github
++project`_. Currently supports v2+
++
++- Register a new application at `Shopify Partners`_, and
++
++- Set the Auth Type to OAuth2 in the application settings
++
++- Set the Application URL to http://[your domain]/login/shopify/
++
++- fill ``API Key`` and ``Shared Secret`` values in your django settings::
++
++      SOCIAL_AUTH_SHOPIFY_KEY   = ''
++      SOCIAL_AUTH_SHOPIFY_SECRET = ''
++
++- fill the scope permissions that you require into the settings `Shopify API`_::
++
++      SOCIAL_AUTH_SHOPIFY_SCOPE = ['write_script_tags',
++                                   'read_orders',
++                                   'write_customers',
++                                   'read_products']
++
++.. _Shopify Partners: http://www.shopify.com/partners
++.. _Shopify API: http://api.shopify.com/authentication.html#scopes
++.. _Github project: https://github.com/Shopify/shopify_python_api
+--- /dev/null
++++ b/docs/backends/sketchfab.rst
+@@ -0,0 +1,17 @@
++Sketchfab
++=========
++
++Sketchfab uses OAuth 2 for authentication.
++
++To use:
++
++- Follow the steps at `Sketchfab Oauth`_, and ask for an
++  ``Authorization code`` grant type.
++
++- Fill the ``Client id/key`` and ``Client Secret`` values you received
++  in your django settings::
++
++      SOCIAL_AUTH_SKETCHFAB_KEY   = ''
++      SOCIAL_AUTH_SKETCHFAB_SECRET = ''
++
++.. _Sketchfab Oauth: https://sketchfab.com/developers/oauth
+--- /dev/null
++++ b/docs/backends/skyrock.rst
+@@ -0,0 +1,21 @@
++Skyrock
++=======
++
++OAuth based Skyrock Connect.
++
++Skyrock offers per application keys named ``Consumer Key`` and ``Consumer
++Secret``. To enable Skyrock these two keys are needed. Further documentation
++at `Skyrock developer resources`_:
++
++- Register a new application at `Skyrock App Creation`_,
++
++- Your callback domain should match your application URL in your application
++  configuration.
++
++- Fill **Consumer Key** and **Consumer Secret** values::
++
++      SOCIAL_AUTH_SKYROCK_KEY = ''
++      SOCIAL_AUTH_SKYROCK_SECRET = ''
++
++.. _Skyrock developer resources: http://www.skyrock.com/developer/
++.. _Skyrock App Creation: https://wwwskyrock.com/developer/application
+--- /dev/null
++++ b/docs/backends/slack.rst
+@@ -0,0 +1,23 @@
++Slack
++=====
++
++Slack
++
++- Register a new application at Slack_, set the callback URL to
++  ``http://example.com/complete/slack/`` replacing ``example.com`` with your
++  domain.
++
++- Fill ``Client ID`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_SLACK_KEY = ''
++      SOCIAL_AUTH_SLACK_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_SLACK_SCOPE = [...]
++
++  See auth scopes at `Slack OAuth docs`_.
++
++
++.. _Slack: https://api.slack.com/applications
++.. _Slack OAuth docs: https://api.slack.com/docs/oauth
+--- /dev/null
++++ b/docs/backends/soundcloud.rst
+@@ -0,0 +1,25 @@
++SoundCloud
++==========
++
++SoundCloud uses OAuth2 for its auth mechanism.
++
++- Register a new application at `SoundCloud App Registration`_, set your
++  application name, website and redirect URI.
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_SOUNDCLOUD_KEY = ''
++      SOCIAL_AUTH_SOUNDCLOUD_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++     SOCIAL_AUTH_SOUNDCLOUD_SCOPE = [...]
++
++Possible scope values are `*` or `non-expiring` according to their `/connect
++documentation`_.
++
++Check the rest of their doc at `SoundCloud Developer Documentation`_.
++
++.. _SoundCloud App Registration: http://soundcloud.com/you/apps/new
++.. _SoundCloud Developer Documentation: http://developers.soundcloud.com/docs
++.. _/connect documentation: http://developers.soundcloud.com/docs/api/reference#connect
+--- /dev/null
++++ b/docs/backends/spotify.rst
+@@ -0,0 +1,25 @@
++Spotify
++=======
++
++Spotify supports OAuth 2.
++
++- Register a new application at `Spotify Web API`_, and follow the
++  instructions below.
++  
++OAuth2
++------
++
++Add the Spotify OAuth2 backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.spotify.SpotifyOAuth2',
++        ...
++    )
++
++- Fill ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_SPOTIFY_KEY = ''
++      SOCIAL_AUTH_SPOTIFY_SECRET = ''
++
++.. _Spotify Web API: https://developer.spotify.com/spotify-web-api
+--- /dev/null
++++ b/docs/backends/stackoverflow.rst
+@@ -0,0 +1,19 @@
++Stackoverflow
++=============
++
++Stackoverflow uses OAuth 2.0
++
++- "Register For An App Key" at the `Stack Exchange API`_ site. Set your OAuth
++  domain and application website settings.
++
++- Add the ``Client Id``, ``Client Secret`` and ``API Key`` values in settings::
++
++    SOCIAL_AUTH_STACKOVERFLOW_KEY = ''
++    SOCIAL_AUTH_STACKOVERFLOW_SECRET = ''
++    SOCIAL_AUTH_STACKOVERFLOW_API_KEY = ''
++
++- You can ask for extra permissions with::
++
++    SOCIAL_AUTH_STACKOVERFLOW_SCOPE = [...]
++
++.. _Stack Exchange API: https://api.stackexchange.com/
+--- /dev/null
++++ b/docs/backends/steam.rst
+@@ -0,0 +1,19 @@
++Steam OpenId
++============
++
++Steam OpenId works quite straightforward, but to retrieve some user data (known
++as ``player`` on Steam API) a Steam API Key is needed.
++
++Configurable settings:
++
++- Supply a Steam API Key from `Steam Dev`_::
++
++    SOCIAL_AUTH_STEAM_API_KEY = key
++
++
++- To save ``player`` data provided by Steam into ``extra_data``::
++
++    SOCIAL_AUTH_STEAM_EXTRA_DATA = ['player']
++
++
++.. _Steam Dev: http://steamcommunity.com/dev/apikey
+--- /dev/null
++++ b/docs/backends/stocktwits.rst
+@@ -0,0 +1,16 @@
++StockTwits
++==========
++
++StockTwits uses OAuth 2 for authentication.
++
++- Register a new application at https://stocktwits.com/developers/apps
++
++- Set the Website URL to http://[your domain]/
++
++- fill ``Consumer Key`` and ``Consumer Secret`` values in your django settings::
++
++      SOCIAL_AUTH_STOCKTWITS_KEY    = ''
++      SOCIAL_AUTH_STOCKTWITS_SECRET = ''
++
++.. _StockTwits authentication docs: http://stocktwits.com/developers/docs/authentication
++.. _StockTwits API: http://stocktwits.com/developers/docs/api
+--- /dev/null
++++ b/docs/backends/strava.rst
+@@ -0,0 +1,17 @@
++Strava
++=========
++
++Strava uses OAuth v2 for Authentication.
++
++- Register a new application at the `Strava API`_, and
++
++- fill ``Client ID`` and ``Client Secret`` from strava.com values in the settings::
++
++      SOCIAL_AUTH_STRAVA_KEY = ''
++      SOCIAL_AUTH_STRAVA_SECRET = ''
++
++- extra scopes can be defined by using::
++
++    SOCIAL_AUTH_STRAVA_SCOPE = ['view_private']
++
++.. _Strava API: https://www.strava.com/settings/api
+--- /dev/null
++++ b/docs/backends/stripe.rst
+@@ -0,0 +1,34 @@
++Stripe
++======
++
++Stripe uses OAuth2 for its authorization service. To setup Stripe backend:
++
++- Register a new application at `Stripe App Creation`_, and
++
++- Grab the ``client_id`` value in ``Applications`` tab and fill the ``App Id``
++  setting::
++
++    SOCIAL_AUTH_STRIPE_KEY = 'ca_...'
++
++- Grab the ``Test Secret Key`` in the ``API Keys`` tab and fille the ``App
++  Secret`` setting::
++
++    SOCIAL_AUTH_STRIPE_SECRET = '...'
++
++- Define ``SOCIAL_AUTH_STRIPE_SCOPE`` with the desired scope (options are
++  ``read_only`` and ``read_write``)::
++
++    SOCIAL_AUTH_STRIPE_SCOPE = ['read_only']
++
++- Add the needed backend to ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.stripe.StripeOAuth2',
++        ...
++    )
++
++More info on Stripe OAuth2 at `Integrating OAuth`_.
++
++.. _Stripe App Creation: https://manage.stripe.com/#account/applications/settings
++.. _Integrating OAuth: https://stripe.com/docs/connect/oauth
+--- /dev/null
++++ b/docs/backends/suse.rst
+@@ -0,0 +1,13 @@
++SUSE
++====
++
++This section describes how to setup the different services provided by SUSE and openSUSE.
++
++
++openSUSE OpenId
++---------------
++
++openSUSE OpenId works straightforward, not settings are needed. Domains or emails
++whitelists can be applied too, check the whitelists_ settings for details.
++
++.. _whitelists: ../configuration/settings.html#whitelists
+--- /dev/null
++++ b/docs/backends/taobao.rst
+@@ -0,0 +1,15 @@
++Taobao OAuth
++============
++
++Taobao OAuth 2.0 workflow.
++
++- Register a new application at Open `Open Taobao`_.
++
++- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings::
++
++      SOCIAL_AUTH_TAOBAO_KEY = ''
++      SOCIAL_AUTH_TAOBAO_SECRET = ''
++
++By default ``token`` is stored in ``extra_data`` field.
++
++.. _Open Taobao: http://open.taobao.com
+--- /dev/null
++++ b/docs/backends/thisismyjam.rst
+@@ -0,0 +1,17 @@
++ThisIsMyJam
++===========
++
++ThisIsMyJam uses OAuth1 for its auth mechanism.
++
++- Register a new application at `ThisIsMyJam App Registration`_, set your
++  application name, website and redirect URI.
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_THISISMYJAM_KEY = ''
++      SOCIAL_AUTH_THISISMYJAM_SECRET = ''
++
++Check the rest of their doc at `ThisIsMyJam API Docs`_.
++
++.. _ThisIsMyJam App Registration: https://www.thisismyjam.com/developers
++.. _ThisIsMyJam API Docs: https://www.thisismyjam.com/developers/docs
+--- /dev/null
++++ b/docs/backends/trello.rst
+@@ -0,0 +1,26 @@
++Trello
++======
++
++Trello provides OAuth1 support for their authentication process.
++
++In order to enable it, follow:
++
++- Generate an Application Key pair at `Trello Developers API Keys`_
++
++- Fill **Consumer Key** and **Consumer Secret** settings::
++
++    SOCIAL_AUTH_TRELLO_KEY = '...'
++    SOCIAL_AUTH_TRELLO_SECRET = '...'
++
++There are also two optional settings:
++
++- your app name, otherwise the authorization page will say "Let An unknown application use your account?"::
++
++    SOCIAL_AUTH_TRELLO_APP_NAME = 'My App'
++
++- the expiration period, social auth defaults to 'never', but you can change it::
++
++    SOCIAL_AUTH_TRELLO_EXPIRATION = '30days'
++
++
++.. _Trello Developers API Keys: https://trello.com/1/appKey/generate
+--- /dev/null
++++ b/docs/backends/tripit.rst
+@@ -0,0 +1,16 @@
++TripIt
++======
++
++TripIt offers per application keys named ``API Key`` and ``API Secret``.
++To enable TripIt these two keys are needed. Further documentation at
++`TripIt Developer Center`_:
++
++- Register a new application at `TripIt App Registration`_,
++
++- fill **API Key** and **API Secret** values::
++
++    SOCIAL_AUTH_TRIPIT_KEY = ''
++    SOCIAL_AUTH_TRIPIT_SECRET = ''
++
++.. _TripIt Developer Center: https://www.tripit.com/developer
++.. _TripIt App Registration: https://www.tripit.com/developer/create
+--- /dev/null
++++ b/docs/backends/tumblr.rst
+@@ -0,0 +1,16 @@
++Tumblr
++======
++
++Tumblr uses OAuth 1.0a for authentication.
++
++- Register a new application at http://www.tumblr.com/oauth/apps
++
++- Set the ``Default callback URL`` to http://[your domain]/
++
++- fill ``OAuth Consumer Key`` and ``Secret Key`` values in your Django
++  settings::
++
++      SOCIAL_AUTH_TUMBLR_KEY = ''
++      SOCIAL_AUTH_TUMBLR_SECRET = ''
++
++.. _Tumblr API: http://www.tumblr.com/docs/en/api/v2
+--- /dev/null
++++ b/docs/backends/twilio.rst
+@@ -0,0 +1,22 @@
++Twilio
++======
++
++- Register a new application at `Twilio Connect Api`_
++
++- Fill ``SOCIAL_AUTH_TWILIO_KEY`` and ``SOCIAL_AUTH_TWILIO_SECRET`` values in
++  the settings::
++
++    SOCIAL_AUTH_TWILIO_KEY = ''
++    SOCIAL_AUTH_TWILIO_SECRET = ''
++
++- Add desired authentication backends to Django's ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``
++  setting::
++
++    'social.backends.twilio.TwilioAuth',
++
++- Usage example::
++
++    <a href="/login/twilio">Enter using Twilio</a>
++
++
++.. _Twilio Connect API: https://www.twilio.com/user/account/connect/apps
+--- /dev/null
++++ b/docs/backends/twitch.rst
+@@ -0,0 +1,19 @@
++Twitch
++======
++
++Twitch works similar to Facebook (OAuth).
++
++- Register a new application in the `connections tab`_ of your Twitch settings
++  page, set the callback URL to ``http://example.com/complete/twitch/``
++  replacing ``example.com`` with your domain.
++
++- Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_TWITCH_KEY = ''
++      SOCIAL_AUTH_TWITCH_SECRET = ''
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_TWITCH_SCOPE = [...]
++
++.. _connections tab: http://www.twitch.tv/settings/connections
+--- /dev/null
++++ b/docs/backends/twitter.rst
+@@ -0,0 +1,34 @@
++Twitter
++=======
++
++Twitter offers per application keys named ``Consumer Key`` and ``Consumer Secret``.
++To enable Twitter these two keys are needed. Further documentation at
++`Twitter development resources`_:
++
++- Register a new application at `Twitter App Creation`_,
++
++- Check the **Allow this application to be used to Sign in with Twitter**
++  checkbox. If you don't check this box, Twitter will force your user to login
++  every time.
++
++- Fill **Consumer Key** and **Consumer Secret** values::
++
++      SOCIAL_AUTH_TWITTER_KEY = ''
++      SOCIAL_AUTH_TWITTER_SECRET = ''
++
++- You need to specify an URL callback or the application will be marked as
++  Client type instead of the Browser. Almost any dummy value will work if
++  you plan some test.
++
++- You can request user's Email address (consult `Twitter verify
++  credentials`_), the parameter is sent automatically, but the
++  applicaton needs to be whitelisted in order to get a valid value.
++
++Twitter usually fails with a 401 error when trying to call the request-token
++URL, this is usually caused by server datetime errors (check miscellaneous
++section). Installing ``ntp`` and syncing the server date with some pool does
++the trick.
++
++.. _Twitter development resources: http://dev.twitter.com/pages/auth
++.. _Twitter App Creation: http://twitter.com/apps/new
++.. _Twitter verify credentials: https://dev.twitter.com/rest/reference/get/account/verify_credentials
+--- /dev/null
++++ b/docs/backends/uber.rst
+@@ -0,0 +1,28 @@
++Uber
++=========
++
++Uber uses OAuth v2 for Authentication.
++
++- Register a new application at the `Uber API`_, and follow the instructions below
++
++OAuth2
++=========
++
++1. Add the Uber OAuth2 backend to your settings page::
++
++      SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++          ...
++          'social.backends.uber.UberOAuth2',
++          ...
++      )
++
++2. Fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_UBER_KEY = ''
++      SOCIAL_AUTH_UBER_SECRET = ''
++
++3. Scope should be defined by using::
++
++    SOCIAL_AUTH_UBER_SCOPE = ['profile', 'request']
++
++.. _Uber API: https://developer.uber.com/dashboard
+--- /dev/null
++++ b/docs/backends/untappd.rst
+@@ -0,0 +1,28 @@
++Untappd
++=======
++
++Untappd uses OAuth v2 for Authentication, check the `official docs`_.
++
++- Create an app by filling out the form here: `Add App`_
++
++- Apps are approved on a one-by-one basis, so you'll need to wait a
++  few days to get your client ID and secret.
++
++- Fill ``Client ID`` and ``Client Secret`` values in the settings::
++
++        SOCIAL_AUTH_UNTAPPD_KEY = '<App UID>'
++        SOCIAL_AUTH_UNTAPPD_SECRET = '<App secret>'
++
++- Add the backend to the ``AUTHENTICATION_BACKENDS`` setting::
++
++        AUTHENTICATION_BACKENDS = (
++            ...
++            'social.backends.untappd.UntappdOAuth2',
++            ...
++        )
++
++- Then you can start using ``{% url social:begin 'untappd' %}`` in
++  your templates
++
++.. _official docs: https://untappd.com/api/docs
++.. _Add App: https://untappd.com/api/register?register=new
+--- /dev/null
++++ b/docs/backends/upwork.rst
+@@ -0,0 +1,28 @@
++Upwork
++======
++
++Upwork supports only OAuth 1.
++
++- Register a new application at `Upwork Developers`_.
++
++OAuth1
++------
++
++Add the Upwork OAuth backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.upwork.UpworkOAuth',
++        ...
++    )
++
++- Fill ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_UPWORK_KEY = ''
++      SOCIAL_AUTH_UPWORK_SECRET = ''
++
++
++**Note:** For more information please go to `Upwork API Reference`_.
++
++.. _Upwork Developers: https://www.upwork.com/services/api/apply
++.. _Upwork API Reference: https://developers.upwork.com/?lang=python
+--- /dev/null
++++ b/docs/backends/username.rst
+@@ -0,0 +1,52 @@
++Username Auth
++=============
++
++python-social-auth_ comes with an UsernameAuth_ backend which comes handy when
++your site uses requires the plain old username and password authentication
++mechanism.
++
++Actually that's a lie since the backend doesn't handle password at all, that's
++up to the developer to validate the password in and the proper place to do it
++is the pipeline, right after the user instance was retrieved or created.
++
++The reason to leave password handling to the developer is because too many
++things are really tied to the project, like the field where the password is
++stored, salt handling, password hashing algorithm and validation. So just add
++the pipeline functions that will do that following the needs of your project.
++
++
++Backend settings
++----------------
++
++``SOCIAL_AUTH_USERNAME_FORM_URL = '/login-form/'``
++    Used to redirect the user to the login/signup form, it must have at least
++    one field named ``username``. Form submit should go to ``/complete/username``,
++    or if it goes to your view, then your view should complete the process
++    calling ``social.actions.do_complete``.
++
++``SOCIAL_AUTH_USERNAME_FORM_HTML = 'login_form.html'``
++    The template will be used to render the login/signup form to the user, it
++    must have at least one field named ``username``. Form submit should go to
++    ``/complete/username``, or if it goes to your view, then your view should
++    complete the process calling ``social.actions.do_complete``.
++
++
++Password handling
++-----------------
++
++Here's an example of password handling to add to the pipeline::
++
++    def user_password(strategy, user, is_new=False, *args, **kwargs):
++        if strategy.backend.name != 'username':
++            return
++
++        password = strategy.request_data()['password']
++        if is_new:
++            user.set_password(password)
++            user.save()
++        elif not user.validate_password(password):
++            # return {'user': None, 'social': None}
++            raise AuthException(strategy.backend)
++
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _UsernameAuth: https://github.com/omab/python-social-auth/blob/master/social/backends/username.py#L5
+--- /dev/null
++++ b/docs/backends/vend.rst
+@@ -0,0 +1,24 @@
++Vend
++====
++
++Vend supports OAuth 2.
++
++- Register a new application at `Vend Developers Portal`_
++  
++- Add the Vend OAuth2 backend to your settings page::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.vend.VendOAuth2',
++        ...
++    )
++
++- Fill ``App Key`` and ``App Secret`` values in the settings::
++
++      SOCIAL_AUTH_VEND_OAUTH2_KEY = ''
++      SOCIAL_AUTH_VEND_OAUTH2_SECRET = ''
++
++More details on their docs_.
++
++.. _Vend Developers Portal: https://developers.vendhq.com/developer/applications
++.. _docs: https://developers.vendhq.com/documentation
+--- /dev/null
++++ b/docs/backends/vimeo.rst
+@@ -0,0 +1,28 @@
++Vimeo
++=====
++
++Vimeo uses OAuth1 to grant access to their API. In order to get the backend
++running follow:
++
++- Register an application at `Vimeo Developer Portal`_ filling the required
++  settings. Ensure to fill ``App Callback URL`` field with
++  ``http://<your hostname>/complete/vimeo/``
++
++- Fill in the **Client Id** and **Client Secret** values in your settings::
++
++    SOCIAL_AUTH_VIMEO_KEY = ''
++    SOCIAL_AUTH_VIMEO_SECRET = ''
++    
++- Specify scopes with::
++
++    SOCIAL_AUTH_VIMEO_SCOPE = [...]
++
++- Add the backend to ``AUTHENTICATION_BACKENDS``::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.vimeo.VimeoOAuth1',
++        ...
++    )
++
++.. _Vimeo Developer Portal: https://developer.vimeo.com/apps/new
+--- /dev/null
++++ b/docs/backends/vk.rst
+@@ -0,0 +1,131 @@
++VK.com (former Vkontakte)
++=========================
++
++VK.com (former Vkontakte) auth service support.
++
++OAuth2
++------
++
++VK.com uses OAuth2 for Authentication.
++
++- Register a new application at the `VK.com API`_,
++
++- fill ``Application Id`` and ``Application Secret`` values in the settings::
++
++      SOCIAL_AUTH_VK_OAUTH2_KEY = ''
++      SOCIAL_AUTH_VK_OAUTH2_SECRET = ''
++
++- Add ``'social.backends.vk.VKOAuth2'`` into your ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``.
++
++- Then you can start using ``/login/vk-oauth2`` in your link href.
++
++- Also it's possible to define extra permissions with::
++
++      SOCIAL_AUTH_VK_OAUTH2_SCOPE = [...]
++
++  See the `VK.com list of permissions`_.
++
++
++OAuth2 Application
++------------------
++
++To support OAuth2 authentication for VK.com applications:
++
++- Create your IFrame application at VK.com.
++
++- In application settings specify your IFrame URL ``mysite.com/vk`` (current
++  default).
++
++- Fill ``Application ID`` and ``Application Secret`` settings::
++
++    SOCIAL_AUTH_VK_APP_KEY = ''
++    SOCIAL_AUTH_VK_APP_SECRET = ''
++
++- Fill ``user_mode``::
++
++    SOCIAL_AUTH_VK_APP_USER_MODE = 2
++
++  Possible values:
++    - ``0``: there will be no check whether a user connected to your
++      application or not
++    - ``1``: ``python-social-auth`` will check ``is_app_user`` parameter
++      VK.com sends when user opens application page one time
++    - ``2``: (safest) ``python-social-auth`` will check status of user
++      interactively (useful when you have interactive authentication via AJAX)
++
++- Add a snippet similar to this into your login template::
++
++    <script src="http://vk.com/js/api/xd_connection.js?2" type="text/javascript"></script>
++    <script type="text/javascript">
++        VK.init(function() {
++                VK.addCallback("onApplicationAdded", requestRights);
++                VK.addCallback("onSettingsChanged", onSettingsChanged);
++            }
++        );
++
++        function startConnect() {
++            VK.callMethod('showInstallBox');
++        }
++
++        function requestRights() {
++            VK.callMethod('showSettingsBox', 1 + 2); // 1+2 is just an example
++        }
++
++        function onSettingsChanged(settings) {
++            window.location.reload();
++        }
++    </script>
++    <a href="#" onclick="startConnect(); return false;">Click to authenticate</a>
++
++To test, launch the server using ``sudo ./manage.py mysite.com:80`` for
++browser to be able to load it when VK.com calls IFrame URL. Open your
++VK.com application page via http://vk.com/app<app_id>. Now you are able to
++connect to application and login automatically after connection when visiting
++application page.
++
++For more details see `authentication for VK.com applications`_
++
++
++OpenAPI
++-------
++
++You can also use VK.com's own OpenAPI to log in, but you need to provide
++HTML template with JavaScript code to authenticate, check below for an example.
++
++- Get an OpenAPI App Id and add it to the settings::
++
++    SOCIAL_AUTH_VK_OPENAPI_ID = ''
++
++  This app id will be passed to the template as ``VK_APP_ID``.
++
++Snippet example::
++
++    <script src="http://vk.com/js/api/openapi.js" type="text/javascript"></script>
++    <script type="text/javascript">
++        var vkAppId = {{ VK_APP_ID|default:"null" }};
++        if (vkAppId) {
++            VK.init({ apiId: vkAppId });
++        }
++        function authVK () {
++            if (!vkAppId) {
++                alert ("Please specify VK.com APP ID in your local settings file");
++                return false;
++            }
++            VK.Auth.login(function(response) {
++                var params = "";
++                if (response.session) {
++                    params = "first_name=" + encodeURI(response.session.user.first_name) + "&last_name=" + encodeURI(response.session.user.last_name);
++                    params += "&nickname=" + encodeURI(response.session.user.nickname) + "&id=" + encodeURI(response.session.user.id);
++                }
++                window.location = "{{ VK_COMPLETE_URL }}?" + params;
++            });
++            return false;
++        }
++    </script>
++    <a href="javascript:void(0);" onclick="authVK();">Click to authorize</a>
++
++
++.. _VK.com OAuth: http://vk.com/dev/authentication
++.. _VK.com list of permissions: http://vk.com/dev/permissions
++.. _VK.com API: http://vk.com/dev/methods
++.. _authentication for VK.com applications: http://www.ikrvss.ru/2011/11/08/django-social-auh-and-vkontakte-application/
+--- /dev/null
++++ b/docs/backends/weibo.rst
+@@ -0,0 +1,23 @@
++Weibo OAuth
++===========
++
++Weibo OAuth 2.0 workflow.
++
++- Register a new application at Weibo_.
++
++- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings::
++
++      SOCIAL_AUTH_WEIBO_KEY = ''
++      SOCIAL_AUTH_WEIBO_SECRET = ''
++
++By default ``account id``, ``profile_image_url`` and ``gender`` are stored in
++extra_data field.
++
++The user name is used by default to build the user instance ``username``,
++sometimes this contains non-ASCII characters which might not be desirable for
++the website. To avoid this issue it's possible to use the Weibo ``domain``
++which will be inside the ASCII range by defining this setting::
++
++    SOCIAL_AUTH_WEIBO_DOMAIN_AS_USERNAME = True
++
++.. _Weibo: http://open.weibo.com
+--- /dev/null
++++ b/docs/backends/withings.rst
+@@ -0,0 +1,13 @@
++Withings
++========
++
++Withings uses OAuth v1 for Authentication.
++
++- Register a new application at the `Withings API`_, and
++
++- fill ``Client ID`` and ``Client Secret`` from withings.com values in the settings::
++
++      SOCIAL_AUTH_WITHINGS_KEY = ''
++      SOCIAL_AUTH_WITHINGS_SECRET = ''
++
++.. _Withings API: https://oauth.withings.com/partner/add
+--- /dev/null
++++ b/docs/backends/wunderlist.rst
+@@ -0,0 +1,13 @@
++Wunderlist
++==========
++
++Wunderlist uses OAuth v2 for Authentication.
++
++- Register a new application at `Wunderlist Developer Portal`_, and
++
++- fill ``Client Id`` and ``Client Secret`` values in the settings::
++
++      SOCIAL_AUTH_WUNDERLIST_KEY = ''
++      SOCIAL_AUTH_WUNDERLIST_SECRET = ''
++
++.. _Wunderlist Developer Portal: https://developer.wunderlist.com/applications
+--- /dev/null
++++ b/docs/backends/xing.rst
+@@ -0,0 +1,14 @@
++XING
++====
++
++XING uses OAuth1 for their auth mechanism, in order to enable the backend
++follow:
++
++- Register a new application at `XING Apps Dashboard`_,
++
++- Fill **Consumer Key** and **Consumer Secret** values::
++
++      SOCIAL_AUTH_XING_KEY = ''
++      SOCIAL_AUTH_XING_SECRET = ''
++
++.. _XING Apps Dashboard: https://dev.xing.com/applications
+--- /dev/null
++++ b/docs/backends/yahoo.rst
+@@ -0,0 +1,33 @@
++Yahoo
++=====
++
++Yahoo supports OpenId and OAuth2 for their auth flow.
++
++
++Yahoo OpenId
++------------
++
++OpenId doesn't require any particular configuration beside enabling the backend
++in the ``AUTHENTICATION_BACKENDS`` setting::
++
++    AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.yahoo.YahooOpenId',
++        ...
++    )
++
++
++Yahoo OAuth2
++------------
++OAuth 2.0 workflow, useful if you are planning to use Yahoo's API.
++
++- Register a new application at `Yahoo Developer Center`_, set your app domain
++  and configure scopes (they can't be overriden by application).
++
++- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings::
++
++      SOCIAL_AUTH_YAHOO_OAUTH2_KEY = ''
++      SOCIAL_AUTH_YAHOO_OAUTH2_SECRET = ''
++
++
++.. _Yahoo Developer Center: https://developer.yahoo.com/
+--- /dev/null
++++ b/docs/backends/yammer.rst
+@@ -0,0 +1,30 @@
++Yammer
++======
++
++Yammer users OAuth2 for their auth mechanism, this application supports Yammer
++OAuth2 in production and staging modes.
++
++Production Mode
++---------------
++
++In order to enable the backend, follow:
++
++
++- Register an application at `Client Applications`_,
++  set the ``Redirect URI`` to ``http://<your hostname>/complete/yammer/``
++
++- Fill **Client Key** and **Client Secret** settings::
++
++    SOCIAL_AUTH_YAMMER_KEY = '...'
++    SOCIAL_AUTH_YAMMER_SECRET = '...'
++
++
++Staging Mode
++------------
++
++Staging mode is configured the same as ``Production Mode``, but settings are
++prefixed with::
++
++    SOCIAL_AUTH_YAMMER_STAGING_*
++
++.. _Client Applications: https://www.yammer.com/client_applications
+--- /dev/null
++++ b/docs/backends/zotero.rst
+@@ -0,0 +1,25 @@
++Zotero
++======
++
++Zotero implements OAuth1 as their authentication mechanism for their Web API v3.
++
++
++1. Go to the `Zotero app registration page`_ to register your application.
++
++2. Fill the **Client ID** and **Client Secret** in your project settings::
++
++    SOCIAL_AUTH_ZOTERO_KEY = '...'
++    SOCIAL_AUTH_ZOTERO_SECRET = '...'
++
++3. Enable the backend::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        ...
++        'social.backends.zotero.ZoteroOAuth',
++        ...
++    )
++
++Further documentation at `Zotero Web API v3 page`_.
++
++.. _Zotero app registration page: https://www.zotero.org/oauth/apps
++.. _Zotero Web API v3 page: https://www.zotero.org/support/dev/web_api/v3/start
+--- /dev/null
++++ b/docs/conf.py
+@@ -0,0 +1,22 @@
++# -*- coding: utf-8 -*-
++extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
++              'sphinx.ext.todo', 'sphinx.ext.viewcode']
++templates_path = ['_templates']
++source_suffix = '.rst'
++master_doc = 'index'
++project = u'Python Social Auth'
++copyright = u'2012, Matías Aguirre'
++exclude_patterns = ['_build']
++pygments_style = 'sphinx'
++html_theme = 'nature'
++html_static_path = []
++htmlhelp_basename = 'PythonSocialAuthdoc'
++latex_documents = [
++  ('index', 'PythonSocialAuth.tex', u'Python Social Auth Documentation',
++   u'Matías Aguirre', 'manual'),
++]
++man_pages = [
++    ('index', 'pythonsocialauth', u'Python Social Auth Documentation',
++     [u'Matías Aguirre'], 1)
++]
++intersphinx_mapping = {'http://docs.python.org/': None}
+--- /dev/null
++++ b/docs/configuration/cherrypy.rst
+@@ -0,0 +1,81 @@
++CherryPy Framework
++==================
++
++CherryPy framework is supported, it works but I'm sure there's room for
++improvements. The implementation uses SQLAlchemy as ORM and expects some values
++accessible on ``cherrypy.request`` for it to work.
++
++At the moment the configuration is expected on ``cherrypy.config`` but ideally
++it should be an application configuration instead.
++
++Expected values are:
++
++``cherrypy.request.user``
++    Current logged in user, load it in your application on a ``before_handler``
++    handler.
++
++``cherrypy.request.db``
++    Current database session, again, load it in your application on
++    a ``before_handler``.
++
++
++Dependencies
++------------
++
++The `CherryPy built-in application` depends on sqlalchemy_, there's no support for
++others ORMs yet but pull-requests are welcome.
++
++
++Enabling the application
++------------------------
++
++The application is defined on ``social.apps.cherrypy_app.views.CherryPyPSAViews``,
++register it in the preferred way for your project.
++
++Check the rest of the docs for the other settings like enabling authentication
++backends and backends keys.
++
++
++Models Setup
++------------
++
++The models are located in ``social.apps.cherrypy_app.models``. A reference to
++your ``User`` model is required to be defined in the project settings, it
++should be an import path, for example::
++
++    cherrypy.config.update({
++        'SOCIAL_AUTH_USER_MODEL': 'models.User'
++    })
++
++
++Login mechanism
++---------------
++
++By default the application sets the session value ``user_id``, this is a simple
++solution and it should be improved, if you want to provider your own login
++mechanism you can do it by defining the ``SOCIAL_AUTH_LOGIN_METHOD`` setting,
++it should be an import path to a callable, like this::
++
++    SOCIAL_AUTH_USER_MODEL = 'app.login_user'
++
++And an example of this function::
++
++    def login_user(strategy, user):
++        strategy.session_set('user_id', user.id)
++
++Then, ensure to load the user in your application at ``cherrypy.request.user``,
++for example::
++
++    def load_user():
++        user_id = cherrypy.session.get('user_id')
++        if user_id:
++            cherrypy.request.user = cherrypy.request.db.query(User).get(user_id)
++        else:
++            cherrypy.request.user = None
++
++
++    cherrypy.tools.authenticate = cherrypy.Tool('before_handler', load_user)
++
++
++.. _CherryPy built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/cherrypy_app
++.. _sqlalchemy: http://www.sqlalchemy.org/
+--- /dev/null
++++ b/docs/configuration/django.rst
+@@ -0,0 +1,213 @@
++Django Framework
++================
++
++Django framework has a little more support since this application was derived
++from `django-social-auth`_. Here are some details on configuring this
++application on Django.
++
++
++Register the application
++------------------------
++
++The `Django built-in app`_ comes with two ORMs, one for default Django ORM and
++another for MongoEngine_ ORM.
++
++Add the application to ``INSTALLED_APPS`` setting, for default ORM::
++
++    INSTALLED_APPS = (
++        ...
++        'social.apps.django_app.default',
++        ...
++    )
++
++And for MongoEngine_ ORM::
++
++    INSTALLED_APPS = (
++        ...
++        'social.apps.django_app.me',
++        ...
++    )
++
++Also ensure to define the MongoEngine_ storage setting::
++
++    SOCIAL_AUTH_STORAGE = 'social.apps.django_app.me.models.DjangoStorage'
++
++
++Database
++--------
++
++(For Django 1.7 and higher) sync database to create needed models::
++
++    ./manage.py migrate
++
++If you're still using South, you'll need override SOUTH_MIGRATION_MODULES_::
++
++    SOUTH_MIGRATION_MODULES = {
++        'default': 'social.apps.django_app.default.south_migrations'
++    }
++
++Note that Django's app labels take the last part of the import, so
++in this case ``social.apps.django_app.default`` becomes ``default`` here.
++
++Sync database to create needed models::
++
++    ./manage.py syncdb
++
++
++Authentication backends
++-----------------------
++
++Add desired authentication backends to Django's AUTHENTICATION_BACKENDS_
++setting::
++
++    AUTHENTICATION_BACKENDS = (
++        'social.backends.open_id.OpenIdAuth',
++        'social.backends.google.GoogleOpenId',
++        'social.backends.google.GoogleOAuth2',
++        'social.backends.google.GoogleOAuth',
++        'social.backends.twitter.TwitterOAuth',
++        'social.backends.yahoo.YahooOpenId',
++        ...
++        'django.contrib.auth.backends.ModelBackend',
++    )
++
++Take into account that backends **must** be defined in AUTHENTICATION_BACKENDS_
++or Django won't pick them when trying to authenticate the user.
++
++Don't miss ``django.contrib.auth.backends.ModelBackend`` if using ``django.contrib.auth``
++application or users won't be able to login by username / password method.
++
++
++URLs entries
++------------
++
++Add URLs entries::
++
++    urlpatterns = patterns('',
++        ...
++        url('', include('social.apps.django_app.urls', namespace='social'))
++        ...
++    )
++
++In case you need a custom namespace, this setting is also needed::
++
++    SOCIAL_AUTH_URL_NAMESPACE = 'social'
++
++
++Template Context Processors
++---------------------------
++
++There's a context processor that will add backends and associations data to
++template context::
++
++    TEMPLATE_CONTEXT_PROCESSORS = (
++        ...
++        'social.apps.django_app.context_processors.backends',
++        'social.apps.django_app.context_processors.login_redirect',
++        ...
++    )
++
++``backends`` context processor will load a ``backends`` key in the context with
++three entries on it:
++
++``associated``
++    It's a list of ``UserSocialAuth`` instances related with the currently
++    logged in user. Will be empty if there's no current user.
++
++``not_associated``
++    A list of available backend names not associated with the current user yet.
++    If there's no user logged in, it will be a list of all available backends.
++
++``backends``
++    A list of all available backend names.
++
++
++ORMs
++----
++
++As detailed above the built-in Django application supports default ORM and
++MongoEngine_ ORM.
++
++When using MongoEngine_ make sure you've followed the instructions for
++`MongoEngine Django integration`_, as you're now utilizing that user model. The
++`MongoEngine_` backend was developed and tested with version 0.6.10 of
++`MongoEngine_`.
++
++Alternate storage models implementations currently follow a tight pattern of
++models that behave near or identical to Django ORM models. It is currently
++not decoupled from this pattern by any abstraction layer. If you would like
++to implement your own alternate, please see the
++``social.apps.django_app.default.models`` and
++``social.apps.django_app.me.models`` modules for guidance.
++
++
++Exceptions Middleware
++---------------------
++
++A base middleware is provided that handles ``SocialAuthBaseException`` by
++providing a message to the user via the Django messages framework, and then
++responding with a redirect to a URL defined in one of the middleware methods.
++
++The middleware is at ``social.apps.django_app.middleware.SocialAuthExceptionMiddleware``.
++Any method can be overridden, but for simplicity these two are recommended::
++
++    get_message(request, exception)
++    get_redirect_uri(request, exception)
++
++By default, the message is the exception message and the URL for the redirect
++is the location specified by the ``LOGIN_ERROR_URL`` setting.
++
++If a valid backend was detected by ``strategy()`` decorator, it will be
++available at ``request.strategy.backend`` and ``process_exception()`` will
++use it to build a backend-dependent redirect URL but fallback to default if not
++defined.
++
++Exception processing is disabled if any of this settings is defined with a
++``True`` value::
++
++    <backend name>_SOCIAL_AUTH_RAISE_EXCEPTIONS = True
++    SOCIAL_AUTH_RAISE_EXCEPTIONS = True
++    RAISE_EXCEPTIONS = True
++    DEBUG = True
++
++The redirect destination will get two ``GET`` parameters:
++
++``message = ''``
++    Message from the exception raised, in some cases it's the message returned
++    by the provider during the auth process.
++
++``backend = ''``
++    Backend name that was used, if it was a valid backend.
++
++
++Django Admin
++------------
++
++The default application (not the MongoEngine_ one) contains an ``admin.py``
++module that will be auto-discovered by the usual mechanism.
++
++But, by the nature of the application which depends on the existence of a user
++model, it's easy to fall in a recursive import ordering making the application
++fail to load. This happens because the admin module will build a set of fields
++to populate the ``search_fields`` property to search for related users in the
++administration UI, but this requires the user model to be retrieved which might
++not be defined at that time.
++
++To avoid this issue define the following setting to circumvent the import
++error::
++
++    SOCIAL_AUTH_ADMIN_USER_SEARCH_FIELDS = ['field1', 'field2']
++
++For example::
++
++    SOCIAL_AUTH_ADMIN_USER_SEARCH_FIELDS = ['username', 'first_name', 'email']
++
++The fields listed **must** be user models fields.
++
++.. _MongoEngine: http://mongoengine.org
++.. _MongoEngine Django integration: http://mongoengine-odm.readthedocs.org/en/latest/django.html
++.. _django-social-auth: https://github.com/omab/django-social-auth
++.. _Django built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/django_app
++.. _AUTHENTICATION_BACKENDS: http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#authentication-backends
++.. _django at dc43fbc: https://github.com/django/django/commit/dc43fbc2f21c12e34e309d0e8a121020391aa03a
++.. _SOUTH_MIGRATION_MODULES: http://south.readthedocs.org/en/latest/settings.html#south-migration-modules
+--- /dev/null
++++ b/docs/configuration/flask.rst
+@@ -0,0 +1,160 @@
++Flask Framework
++===============
++
++Flask reusable applications are tricky (or I'm not capable enough). Here are
++details on how to enable this application on Flask.
++
++
++Dependencies
++------------
++
++The `Flask built-in app` depends on sqlalchemy_, there's initial support for
++MongoEngine_ ORM too (check below for more details).
++
++
++Enabling the application
++------------------------
++
++The applications define a `Flask Blueprint`_, which needs to be registered once
++the Flask app is configured by::
++
++    from social.apps.flask_app.routes import social_auth
++
++    app.register_blueprint(social_auth)
++
++For MongoEngine_ you need this setting::
++
++    SOCIAL_AUTH_STORAGE = 'social.apps.flask_app.me.models.FlaskStorage'
++
++
++Models Setup
++------------
++
++At the moment the models for python-social-auth_ are defined inside a function
++because they need the reference to the current db instance and the User model
++used on your project (check *User model reference* below). Once the Flask app
++and the database are defined, call ``init_social`` to register the models::
++
++    from social.apps.flask_app.default.models import init_social
++
++    init_social(app, db)
++
++For MongoEngine_::
++
++    from social.apps.flask_app.me.models import init_social
++
++    init_social(app, db)
++
++So far I wasn't able to find another way to define the models on another way
++rather than making it as a side-effect of calling this function since the
++database is not available and ``current_app`` cannot be used on init time, just
++run time.
++
++
++User model reference
++--------------------
++
++The application keeps a reference to the User model used by your project,
++define it by using this setting::
++
++    SOCIAL_AUTH_USER_MODEL = 'foobar.models.User'
++
++The value must be the import path to the User model.
++
++
++Global user
++-----------
++
++The application expects the current logged in user accesible at ``g.user``,
++define a handler like this to ensure that::
++
++    @app.before_request
++    def global_user():
++        g.user = get_current_logged_in_user
++
++
++Flask-Login
++-----------
++
++The application works quite well with Flask-Login_, ensure to have some similar
++handlers to these::
++
++    @login_manager.user_loader
++    def load_user(userid):
++        try:
++            return User.query.get(int(userid))
++        except (TypeError, ValueError):
++            pass
++
++
++    @app.before_request
++    def global_user():
++        g.user = login.current_user
++
++
++    # Make current user available on templates
++    @app.context_processor
++    def inject_user():
++        try:
++            return {'user': g.user}
++        except AttributeError:
++            return {'user': None}
++
++
++Remembering sessions
++--------------------
++
++The users session can be remembered when specified on login. The common
++implementation for this feature is to pass a parameter from the login form
++(``remember_me``, ``keep``, etc), to flag the action. Flask-Login_ will mark
++the session as persistent if told so.
++
++python-social-auth_ will check for a given name (``keep``) by default, but
++since providers won't pass parameters back to the application, the value must
++be persisted in the session before the authentication process happens.
++
++So, the following setting is required for this to work::
++
++    SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ['keep']
++
++It's possible to override the default name with this setting::
++
++    SOCIAL_AUTH_REMEMBER_SESSION_NAME = 'remember_me'
++
++Don't use the value ``remember`` since that will clash with Flask-Login_ which
++pops the value from the session.
++
++Then just pass the parameter ``keep=1`` as a GET or POST parameter.
++
++
++Exceptions handling
++-------------------
++
++The Django application has a middleware (that fits in the framework
++architecture) to facilitate the different exceptions_ handling raised by
++python-social-auth_. The same can be accomplished (even on a simpler way) in
++Flask by defining an errorhandler_. For example the next code will redirect any
++social-auth exception to a ``/socialerror`` URL::
++
++    from social.exceptions import SocialAuthBaseException
++
++
++    @app.errorhandler(500)
++    def error_handler(error):
++        if isinstance(error, SocialAuthBaseException):
++            return redirect('/socialerror')
++
++
++Be sure to set your debug and test flags to ``False`` when testing this on your
++development environment, otherwise the exception will be raised and error
++handlers won't be called.
++
++
++.. _Flask Blueprint: http://flask.pocoo.org/docs/blueprints/
++.. _Flask-Login: https://github.com/maxcountryman/flask-login
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _Flask built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/flask_app
++.. _sqlalchemy: http://www.sqlalchemy.org/
++.. _exceptions: https://github.com/omab/python-social-auth/blob/master/social/exceptions.py
++.. _errorhandler: http://flask.pocoo.org/docs/api/#flask.Flask.errorhandler
++.. _MongoEngine: http://mongoengine.org
+--- /dev/null
++++ b/docs/configuration/index.rst
+@@ -0,0 +1,24 @@
++Configuration
++=============
++
++All the apps share the settings names, some settings for Django framework are
++special (like ``AUTHENTICATION_BACKENDS``).
++
++Below there's a main settings document detailing each configuration and its
++purpose, plus sections detailed for each framework and their particularities.
++
++Support for more frameworks will be added in the future, pull-requests are very
++welcome.
++
++Contents:
++
++.. toctree::
++   :maxdepth: 2
++
++   settings
++   django
++   flask
++   pyramid
++   cherrypy
++   webpy
++   porting_from_dsa
+--- /dev/null
++++ b/docs/configuration/porting_from_dsa.rst
+@@ -0,0 +1,145 @@
++Porting from django-social-auth
++===============================
++
++
++Being a derivative work from django-social-auth_, porting from it to
++python-social-auth_ should be an easy task. Porting to others libraries usually
++is a pain, I'm trying to make this as easy as possible.
++
++
++Installed apps
++--------------
++
++On django-social-auth_ there was a single application to add into
++``INSTALLED_APPS`` plus a setting to define which ORM to be used (default or
++MongoEngine). Now the apps are split and there's not need for that extra
++setting.
++
++When using the default ORM::
++
++    INSTALLED_APPS = (
++        ...
++        'social.apps.django_app.default',
++        ...
++    )
++
++And when using MongoEngine::
++
++    INSTALLED_APPS = (
++        ...
++        'social.apps.django_app.me',
++        ...
++    )
++
++The models table names were defined to be compatible with those used on
++django-social-auth_, so data is not needed to be migrated.
++
++
++URLs
++----
++
++The URLs are namespaced, you can chose your namespace, the `example app`_ uses
++the ``social`` namespace. Replace the old include with::
++
++    urlpatterns = patterns('',
++        ...
++        url('', include('social.apps.django_app.urls', namespace='social'))
++        ...
++    )
++
++On templates use a namespaced URL::
++
++    {% url 'social:begin' "google-oauth2" %}
++
++Account disconnection URL would be::
++
++    {% url 'social:disconnect_individual' provider, id %}
++
++
++Porting settings
++----------------
++
++All python-social-auth_ settings are prefixed with ``SOCIAL_AUTH_``, except for
++some exception on Django framework, ``AUTHENTICATION_BACKENDS`` remains the
++same for obvious reasons.
++
++All backends settings have the backend name into it, all uppercase and with
++dashes replaced with underscores, take for instance Google OAuth2 backend is
++named ``google-oauth2``, any setting name related to that backend should start
++with ``SOCIAL_AUTH_GOOGLE_OAUTH2_``.
++
++Keys and secrets are some mandatory settings needed for OAuth providers, to
++keep consistency the names follow the same naming convention ``*_KEY`` for the
++application key, and ``*_SECRET`` for the secret. OAuth1 backends use to have
++``CONSUMER`` in the setting name, not anymore. Following with the Google OAuth2
++example::
++
++    SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '...'
++    SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '...'
++
++Remember that the name of the backend is needed in the settings, and names
++differ a little from backend to backend, like `Facebook OAuth2 backend`_ name
++is ``facebook``. So the settings should be::
++
++    SOCIAL_AUTH_FACEBOOK_KEY = '...'
++    SOCIAL_AUTH_FACEBOOK_SECRET = '...'
++
++
++Authentication backends
++-----------------------
++
++Import path for authentication backends changed a little, there's no more
++``contrib`` module, there's no need for it. Some backends changed the names to
++have some consistency, check the backends, it should be easy to track the names
++changes. Examples of the new import paths::
++
++    AUTHENTICATION_BACKENDS = (
++        'social.backends.open_id.OpenIdAuth',
++        'social.backends.google.GoogleOpenId',
++        'social.backends.google.GoogleOAuth2',
++        'social.backends.google.GoogleOAuth',
++        'social.backends.twitter.TwitterOAuth',
++        'social.backends.facebook.FacebookOAuth2',
++    )
++
++
++Session
++-------
++
++Django stores the last authentication backend used in the user session as an
++import path, this can cause import troubles when porting since the old import
++paths aren't valid anymore. Some solutions to this problem are:
++
++1. Clean the session and force the users to login again in your site
++
++2. Run a migration script that will update the authentication backend session
++   value for each session in your database. This implies figuring out the new
++   import path for each backend you have configured, which is the value used in
++   ``AUTHENTICATION_BACKENDS`` setting.
++
++   `@tomgruner`_ created a Gist here_ that updates the value just for Facebook
++   backend. A ``template`` for this script would look like this::
++
++    from django.contrib.sessions.models import Session
++
++    BACKENDS = {
++        'social_auth.backends.facebook.FacebookBackend': 'social.backends.facebook.FacebookOAuth2'
++    }
++
++    for sess in Session.objects.iterator():
++        session_dict = sess.get_decoded()
++
++        if '_auth_user_backend' in session_dict.keys():
++            # Change old backend import path from new backend import path
++            if session_dict['_auth_user_backend'].startswith('social_auth'):
++                session_dict['_auth_user_backend'] = BACKENDS[session_dict['_auth_user_backend']]
++                new_sess = Session.objects.save(sess.session_key, session_dict, sess.expire_date)
++                print 'New session saved {}'.format(new_sess.pk)
++
++
++.. _django-social-auth: https://github.com/omab/django-social-auth
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _example app: https://github.com/omab/python-social-auth/blob/master/examples/django_example/example/urls.py#L17
++.. _Facebook OAuth2 backend: https://github.com/omab/python-social-auth/blob/master/social/backends/facebook.py#L29
++.. _ at tomgruner: https://github.com/tomgruner
++.. _here: https://gist.github.com/tomgruner/5ce8bb1f4c55d17b5b25
+--- /dev/null
++++ b/docs/configuration/pyramid.rst
+@@ -0,0 +1,137 @@
++Pyramid Framework
++=================
++
++Pyramid_ reusable applications are tricky (or I'm not capable enough). Here are
++details on how to enable this application on Pyramid.
++
++
++Dependencies
++------------
++
++The `Pyramid built-in app`_ depends on sqlalchemy_, there's no support for others
++ORMs yet but pull-requests are welcome.
++
++
++Enabling the application
++------------------------
++
++The application can be scanned by ``Configurator.scan()``, also it defines an
++``includeme()`` in the ``__init__.py`` file which will add the needed routes to
++your application configuration. To scan it just add::
++
++    config.include('social.apps.pyramid_app')
++    config.scan('social.apps.pyramid_app')
++
++
++Models Setup
++------------
++
++At the moment the models for python-social-auth_ are defined inside a function
++because they need the reference to the current DB instance and the User model
++used on your project (check *User model reference* below). Once the Pyramid
++application configuration and database are defined, call ``init_social`` to
++register the models::
++
++    from social.apps.pyramid_app.models import init_social
++
++    init_social(config, Base, DBSession)
++
++So far I wasn't able to find another way to define the models on another way
++rather than making it as a side-effect of calling this function since the
++database is not available and ``current_app`` cannot be used on initialization
++time, just run time.
++
++
++User model reference
++--------------------
++
++The application keeps a reference to the User model used by your project,
++define it by using this setting::
++
++    SOCIAL_AUTH_USER_MODEL = 'foobar.models.User'
++
++The value must be the import path to the User model.
++
++
++Global user
++-----------
++
++The application expects the current logged in user accessible at ``request.user``,
++the example application ensures that with this hander::
++
++    def get_user(request):
++        user_id = request.session.get('user_id')
++        if user_id:
++            user = DBSession.query(User)\
++                            .filter(User.id == user_id)\
++                            .first()
++        else:
++            user = None
++        return user
++
++The handler is added to the configuration doing::
++
++    config.add_request_method('example.auth.get_user', 'user', reify=True)
++
++This is just a simple example, probably your project does it in a better way.
++
++
++User login
++----------
++
++Since the application doesn't make any assumption on how you are going to login
++the users, you need to specify it. In order to do that, define these settings::
++
++    SOCIAL_AUTH_LOGIN_FUNCTION = 'example.auth.login_user'
++    SOCIAL_AUTH_LOGGEDIN_FUNCTION = 'example.auth.login_required'
++
++The first one must accept the strategy used and the user instance that was
++created or retrieved from the database, there you can set the user id in the
++session or cookies or whatever place used later to retrieve the id again and
++load the user from the database (check the snippet above in *Global User*).
++
++The second one is used to ensure that there's a user logged in when calling the
++disconnect view. It must accept a ``User`` instance and return ``True`` or
++``Flase``.
++
++Check the auth.py_ in the example application for details on how it's done
++there.
++
++
++Social auth in templates context
++--------------------------------
++
++To access the social instances related to a user in the template context, you
++can do so by accessing the ``social_auth`` attribute in the user instance::
++
++    <li tal:repeat="social request.user.social_auth">${social.provider}</li>
++
++Also you can add the backends (associated and not associated to a user) by
++enabling this context function in your project::
++
++    from pyramid.events import subscriber, BeforeRender
++    from social.apps.pyramid_app.utils import backends
++
++    @subscriber(BeforeRender)
++    def add_social(event):
++        request = event['request']
++        event.update(backends(request, request.user))
++
++That will load a dict with entries::
++
++    {
++        'associated': [...],
++        'not_associated': [...],
++        'backends': [...]
++    }
++
++The ``associated`` key will have all the associated ``UserSocialAuth``
++instances related to the given user. ``not_associated`` will have the backends
++names not associated and backends will have all the enabled backends names.
++
++
++.. _Pyramid: http://www.pylonsproject.org/projects/pyramid/about
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _Pyramid built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/pyramid_app
++.. _sqlalchemy: http://www.sqlalchemy.org/
++.. _auth.py: https://github.com/omab/python-social-auth/blob/master/examples/pyramid_example/example/auth.py
+--- /dev/null
++++ b/docs/configuration/settings.rst
+@@ -0,0 +1,311 @@
++Configuration
++=============
++
++Application setup
++-----------------
++
++Once the application is installed (check Installation_) define the following
++settings to enable the application behavior. Also check the sections dedicated
++to each framework for detailed instructions.
++
++
++Settings name
++-------------
++
++Almost all settings are prefixed with ``SOCIAL_AUTH_``, there are some
++exceptions for Django framework like ``AUTHENTICATION_BACKENDS``.
++
++All settings can be defined per-backend by adding the backend name to the
++setting name like ``SOCIAL_AUTH_TWITTER_LOGIN_URL``. Settings discovery is done
++by reducing the name starting with backend setting, then app setting and
++finally global setting, for example::
++
++    SOCIAL_AUTH_TWITTER_LOGIN_URL
++    SOCIAL_AUTH_LOGIN_URL
++    LOGIN_URL
++
++The backend name is generated from the ``name`` attribute from the backend
++class by uppercasing it and replacing ``-`` with ``_``.
++
++
++Keys and secrets
++----------------
++
++- Setup needed OAuth keys (see OAuth_ section for details)::
++
++    SOCIAL_AUTH_TWITTER_KEY = 'foobar'
++    SOCIAL_AUTH_TWITTER_SECRET = 'bazqux'
++
++OpenId backends don't require keys usually, but some need some API Key to
++call any API on the provider. Check Backends_ sections for details.
++
++
++Authentication backends
++-----------------------
++
++Register the backends you plan to use, on Django framework use the usual
++``AUTHENTICATION_BACKENDS`` settings, for others, define
++``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``::
++
++    SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
++        'social.backends.open_id.OpenIdAuth',
++        'social.backends.google.GoogleOpenId',
++        'social.backends.google.GoogleOAuth2',
++        'social.backends.google.GoogleOAuth',
++        'social.backends.twitter.TwitterOAuth',
++        'social.backends.yahoo.YahooOpenId',
++        ...
++    )
++
++
++URLs options
++------------
++
++These URLs are used on different steps of the auth process, some for successful
++results and others for error situations.
++
++``SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/logged-in/'``
++    Used to redirect the user once the auth process ended successfully. The
++    value of ``?next=/foo`` is used if it was present
++
++``SOCIAL_AUTH_LOGIN_ERROR_URL = '/login-error/'``
++    URL where the user will be redirected in case of an error
++
++``SOCIAL_AUTH_LOGIN_URL = '/login-url/'``
++    Is used as a fallback for ``LOGIN_ERROR_URL``
++
++``SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/new-users-redirect-url/'``
++    Used to redirect new registered users, will be used in place of
++    ``SOCIAL_AUTH_LOGIN_REDIRECT_URL`` if defined. Note that ``?next=/foo`` is appended if present,
++    if you want new users to go to next, you'll need to do it yourself.
++
++``SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = '/new-association-redirect-url/'``
++    Like ``SOCIAL_AUTH_NEW_USER_REDIRECT_URL`` but for new associated accounts
++    (user is already logged in). Used in place of ``SOCIAL_AUTH_LOGIN_REDIRECT_URL``
++
++``SOCIAL_AUTH_DISCONNECT_REDIRECT_URL = '/account-disconnected-redirect-url/'``
++    The user will be redirected to this URL when a social account is
++    disconnected
++
++``SOCIAL_AUTH_INACTIVE_USER_URL = '/inactive-user/'``
++    Inactive users can be redirected to this URL when trying to authenticate.
++
++Successful URLs will default to ``SOCIAL_AUTH_LOGIN_URL`` while error URLs will
++fallback to ``SOCIAL_AUTH_LOGIN_ERROR_URL``.
++
++
++User model
++----------
++
++``UserSocialAuth`` instances keep a reference to the ``User`` model of your
++project, since this is not known, the ``User`` model must be configured by
++a setting::
++
++    SOCIAL_AUTH_USER_MODEL = 'foo.bar.User'
++
++``User`` model must have a ``username`` and ``email`` field, these are
++required.
++
++Also an ``is_authenticated`` and ``is_active`` boolean flags are recommended,
++these can be methods if necessary (must return ``True`` or ``False``). If the
++model lacks them a ``True`` value is assumed.
++
++
++Tweaking some fields length
++---------------------------
++
++Some databases impose limitations on index columns (like MySQL InnoDB). These
++limitations won't play nice on some ``UserSocialAuth`` fields. To avoid such
++errors, define some of the following settings.
++
++``SOCIAL_AUTH_UID_LENGTH = <int>``
++    Used to define the max length of the field `uid`. A value of 223 should work
++    when using MySQL InnoDB which impose a 767 bytes limit (assuming UTF-8
++    encoding).
++
++``SOCIAL_AUTH_NONCE_SERVER_URL_LENGTH = <int>``
++    ``Nonce`` model has a unique constraint over ``('server_url', 'timestamp',
++    'salt')``, salt has a max length of 40, so ``server_url`` length must be
++    tweaked using this setting.
++
++``SOCIAL_AUTH_ASSOCIATION_SERVER_URL_LENGTH = <int>`` or ``SOCIAL_AUTH_ASSOCIATION_HANDLE_LENGTH = <int>``
++    ``Association`` model has a unique constraint over ``('server_url',
++    'handle')``, both fields lengths can be tweaked by these settings.
++
++
++Username generation
++-------------------
++
++Some providers return a username, others just an ID or email or first and last
++names. The application tries to build a meaningful username when possible but
++defaults to generating one if needed.
++
++A UUID is appended to usernames in case of collisions. Here are some settings
++to control username generation.
++
++``SOCIAL_AUTH_UUID_LENGTH = 16``
++    This controls the length of the UUID appended to usernames.
++
++``SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True``
++    If you want to use the full email address as the ``username``, define this
++    setting.
++
++``SOCIAL_AUTH_SLUGIFY_USERNAMES = False``
++    For those that prefer slugged usernames, the ``get_username`` pipeline can
++    apply a slug transformation (code borrowed from Django project) by defining
++    this setting to ``True``. The feature is disabled by default to to not
++    force this option to all projects.
++
++``SOCIAL_AUTH_CLEAN_USERNAMES = True``
++    By default the regex ``r'[^\w. at +-_]+'`` is applied over usernames to clean
++    them from usual undesired characters like spaces. Set this setting to
++    ``False`` to disable this behavior.
++
++
++Extra arguments on auth processes
++---------------------------------
++
++Some providers accept particular GET parameters that produce different results
++during the auth process, usually used to show different dialog types (mobile
++version, etc).
++
++You can send extra parameters on auth process by defining settings per backend,
++example to request Facebook to show Mobile authorization page, define::
++
++      FACEBOOK_AUTH_EXTRA_ARGUMENTS = {'display': 'touch'}
++
++For other providers, just define settings in the form::
++
++      SOCIAL_AUTH_<uppercase backend name>_AUTH_EXTRA_ARGUMENTS = {...}
++
++Also, you can send extra parameters on request token process by defining
++settings in the same way explained above but with this other suffix::
++
++      SOCIAL_AUTH_<uppercase backend name>_REQUEST_TOKEN_EXTRA_ARGUMENTS = {...}
++
++Basic information is requested to the different providers in order to create
++a coherent user instance (with first and last name, email and full name), this
++could be too intrusive for some sites that want to ask users the minimum data
++possible. It's possible to override the default values requested by defining
++any of the following settings, for Open Id providers::
++
++    SOCIAL_AUTH_<BACKEND_NAME>_IGNORE_DEFAULT_AX_ATTRS = True
++    SOCIAL_AUTH_<BACKEND_NAME>_AX_SCHEMA_ATTRS = [
++        (schema, alias)
++    ]
++
++For OAuth backends::
++
++    SOCIAL_AUTH_<BACKEND_NAME>_IGNORE_DEFAULT_SCOPE = True
++    SOCIAL_AUTH_<BACKEND_NAME>_SCOPE = [
++        ...
++    ]
++
++
++Processing redirects and urlopen
++--------------------------------
++
++The application issues several redirects and API calls. The following settings
++allow some tweaks to the behavior of these.
++
++``SOCIAL_AUTH_SANITIZE_REDIRECTS = False``
++    The auth process finishes with a redirect, by default it's done to the
++    value of ``SOCIAL_AUTH_LOGIN_REDIRECT_URL`` but can be overridden with
++    ``next`` GET argument. If this setting is ``True``, this application will
++    vary the domain of the final URL and only redirect to it if it's on the
++    same domain.
++
++``SOCIAL_AUTH_REDIRECT_IS_HTTPS = False``
++    On projects behind a reverse proxy that uses HTTPS, the redirect URIs
++    can have the wrong schema (``http://`` instead of ``https://``) if
++    the request lacks the appropriate headers, which might cause errors during
++    the auth process. To force HTTPS in the final URIs set this setting to
++    ``True``
++
++``SOCIAL_AUTH_URLOPEN_TIMEOUT = 30``
++    Any ``urllib2.urlopen`` call will be performed with the default timeout
++    value, to change it without affecting the global socket timeout define this
++    setting (the value specifies timeout seconds).
++
++    ``urllib2.urlopen`` uses ``socket.getdefaulttimeout()`` value by default, so
++    setting ``socket.setdefaulttimeout(...)`` will affect ``urlopen`` when this
++    setting is not defined, otherwise this setting takes precedence. Also this
++    might affect other places in Django.
++
++    ``timeout`` argument was introduced in python 2.6 according to `urllib2
++    documentation`_
++
++
++Whitelists
++----------
++
++Registration can be limited to a set of users identified by their email
++address or domain name. To white-list just set any of these settings:
++
++``SOCIAL_AUTH_<BACKEND_NAME>_WHITELISTED_DOMAINS = ['foo.com', 'bar.com']``
++    Supply a list of domain names to be white-listed. Any user with an email
++    address on any of the allowed domains will login successfully, otherwise
++    ``AuthForbidden`` is raised.
++
++``SOCIAL_AUTH_<BACKEND_NAME>_WHITELISTED_EMAILS = ['me at foo.com', 'you at bar.com']``
++    Supply a list of email addresses to be white-listed. Any user with an email
++    address in this list will login successfully, otherwise ``AuthForbidden``
++    is raised.
++
++
++Miscellaneous settings
++----------------------
++
++``SOCIAL_AUTH_PROTECTED_USER_FIELDS = ['email',]``
++    During the pipeline process a ``dict`` named ``details`` will be populated
++    with the needed values to create the user instance, but it's also used to
++    update the user instance. Any value in it will be checked as an attribute
++    in the user instance (first by doing ``hasattr(user, name)``). Usually
++    there are attributes that cannot be updated (like ``username``, ``id``,
++    ``email``, etc.), those fields need to be *protect*. Set any field name that
++    requires *protection* in this setting, and it won't be updated.
++
++``SOCIAL_AUTH_SESSION_EXPIRATION = False``
++    By default, user session expiration time will be set by your web
++    framework (in Django, for example, it is set with
++    `SESSION_COOKIE_AGE`_). Some providers return the time that the
++    access token will live, which is stored in ``UserSocialAuth.extra_data``
++    under the key ``expires``. Changing this setting to True will override your
++    web framework's session length setting and set user session lengths to
++    match the ``expires`` value from the auth provider.
++
++``SOCIAL_AUTH_OPENID_PAPE_MAX_AUTH_AGE = <int value>``
++    Enable `OpenID PAPE`_ extension support by defining this setting.
++
++``SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ['foo',]``
++    If you want to store extra parameters from POST or GET in session, like it
++    was made for ``next`` parameter, define this setting with the parameter
++    names.
++
++    In this case ``foo`` field's value will be stored when user follows this
++    link ``<a href="{% url socialauth_begin 'github' %}?foo=bar">...</a>``.
++
++``SOCIAL_AUTH_PASSWORDLESS = False``
++    When this setting is ``True`` and ``social.pipeline.mail.send_validation``
++    is enabled, it allows the implementation of a `passwordless authentication
++    mechanism`_. Example of this implementation can be found at
++    psa-passwordless_.
++
++
++Account disconnection
++---------------------
++
++Disconnect is an side-effect operation and should be done by POST method only,
++some CSRF protection is encouraged (and enforced on Django app). Ensure that
++any call to `/disconnect/<backend>/` or `/disconnect/<backend>/<id>/` is done
++using POST.
++
++
++.. _urllib2 documentation: http://docs.python.org/library/urllib2.html#urllib2.urlopen
++.. _OpenID PAPE: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0.html
++.. _Installation: ../installing.html
++.. _Backends: ../backends/index.html
++.. _OAuth: http://oauth.net/
++.. _passwordless authentication mechanism: https://medium.com/@ninjudd/passwords-are-obsolete-9ed56d483eb
++.. _psa-passwordless: https://github.com/omab/psa-passwordless
++.. _SESSION_COOKIE_AGE: https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-SESSION_COOKIE_AGE
+--- /dev/null
++++ b/docs/configuration/webpy.rst
+@@ -0,0 +1,74 @@
++Webpy Framework
++===============
++
++Webpy_ framework is easy to setup, once that python-social-auth_ is installed
++or accessible in the ``PYTHONPATH``, just add the needed configurations to make
++it run.
++
++
++Dependencies
++------------
++
++The `Webpy built-in app` depends on sqlalchemy_, there's no support for others
++ORMs yet but pull-requests are welcome.
++
++
++Configuration
++-------------
++
++Add the needed settings into ``web.config`` store. Settings are prefixed with
++``SOCIAL_AUTH_`` but there's a helper for it::
++
++    from social.utils import setting_name
++
++    web.config[setting_name('USER_MODEL')] = 'models.User'
++    web.config[setting_name('LOGIN_REDIRECT_URL')] = '/done/'
++    web.config[setting_name('AUTHENTICATION_BACKENDS')] = (
++        'social.backends.google.GoogleOAuth2',
++        ...
++    )
++
++Add all the settings needed for the app (check Configuration_ section for
++details).
++
++
++URLs
++----
++
++Add the social application into URLs::
++
++    from social.apps.webpy_app import app as social_app
++
++    urls = (
++        ...
++        '', social_app.app_social
++        ...
++    )
++
++
++Session
++-------
++
++python-social-auth_ depends on sessions storage to keep some essential values,
++usually redirects and ``state`` parameters used to validate authentication
++process on OAuth providers.
++
++The `Webpy built-in app` expects the session reference to be available under
++``web.web_session`` so ensure it's available there.
++
++
++User model
++----------
++
++Like the other apps, the User model must be defined on settings since
++a reference to it is kept on ``UserSocialAuth`` instance. Define like this::
++
++    web.config[setting_name('USER_MODEL')] = 'models.User'
++
++Where the value is the import path to the User model used on your project.
++
++
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _Webpy: http://webpy.org/
++.. _Webpy built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/webpy_app
++.. _sqlalchemy: http://www.sqlalchemy.org/
+--- /dev/null
++++ b/docs/copyright.rst
+@@ -0,0 +1,12 @@
++Copyrights and Licence
++======================
++
++``python-social-auth`` is protected by BSD licence. Check the LICENCE_ for
++details.
++
++The base work was derived from django-social-auth_ work and copyrighted too,
++check `django-social-auth LICENCE`_ for details:
++
++.. _LICENCE: https://github.com/omab/python-social-auth/blob/master/LICENSE
++.. _django-social-auth: https://github.com/omab/django-social-auth
++.. _django-social-auth LICENCE: https://github.com/omab/django-social-auth/blob/master/LICENSE
+--- /dev/null
++++ b/docs/developer_intro.rst
+@@ -0,0 +1,170 @@
++Beginners Guide
++===============
++
++This is an attempt to bring together a number of concepts in python-social-auth
++(psa) so that you will understand how it fits into your system. This definitely
++has a Django flavor to it (because that's how I learned it).
++
++Understanding PSA URLs
++-----------------------
++
++If you have not seen namespaced URLs before, you are about to be introduced.
++When you add the PSA entry to your urls.py, it looks like this::
++
++    url(r'', include('social.apps.django_app.urls', namespace='social'))
++
++that "namespace" part on the end is what keeps the names in the PSA-world from
++colliding with the names in your app, or other 3rd-party apps.  So your login
++link will look like this::
++
++    <a href="{% url 'social:begin' 'provider-name' %}">Login</a>
++
++(See how "social" in the URL mapping matches the value of "namespace" in the
++urls.py entry?)
++
++Understanding Backends
++----------------------
++
++PSA implements a lot of backends.  Find the entry in the docs for your backend,
++and if it's there, follow the steps to enable it, which come down to
++
++1) Set up SOCIAL_AUTH_{backend} variables in settings.py.  (The
++   settings vary, based on the backends)
++
++2) Adding your backend to AUTHENTICATION_BACKENDS in settings.py.
++
++If you need to implement a different backend (for instance, let's say you
++want to use Intuit's OpenID), you can subclass the nearest one and override
++the "name" attribute::
++
++    from social.backends.open_id import OpenIDAuth
++
++    class IntuitOpenID(OpenIDAuth):
++        name = 'intuit'
++
++And then add your new backend to AUTHENTICATION_BACKENDS in settings.py.
++
++A couple notes about the pipeline:
++
++The standard pipeline does not log the user in until after the pipeline has
++completed.  So if you get a value in the user key of the accumulative
++dictionary, that implies that the user was logged in when the process started.
++
++Understanding the Pipeline
++--------------------------
++
++Reversing a URL like ``{% url 'social:begin' 'github' %}`` will give you a url
++like::
++
++    http://example.com/login/github
++
++And clicking on that link will cause the "pipeline" to be started. The pipeline
++is a list of functions that build up data about the user as we go through the
++steps of the authentication process.  (If you really want to understand the
++pipeline, look at the source in ``social/backends/base.py``, and see the
++``run_pipeline()`` function in ``BaseAuth``.)
++
++The design contract for each function in the pipeline is:
++
++1) The pipeline starts with a four-item dictionary (the accumulative dictionary)
++   which is updated with the results of each function in the pipeline. The
++   initial four values are:
++
++   ``strategy``
++     contains a strategy object
++   ``backend``
++     contains the backend being used during this pipeline run
++   ``request``
++     contains a dictionary of the request keys. Note to Django users -- this is
++     not an HttpRequest object, it is actually the results of
++     ``request.REQUEST``.
++   ``details``
++     which is an empty dict.
++
++2) If the function returns a dictionary or something False-ish, add the contents
++   of the dictionary to an accumulative dictionary (called ``out`` in
++   ``run_pipeline``), and call the next step in the pipeline with the
++   accumulative dictionary.
++
++3) If something else is returned (for example, a subclass of ``HttpResponse``),
++   then return that to the browser.
++
++4) If the pipeline completes, *THEN* the user is authenticated (logged in). So
++   if you are finding an authenticated user object while the pipeline is
++   running, that means that the user was logged in when the pipeline started.
++
++There is one pipeline for your site as a whole -- if you have backend-specific
++logic, you have to make your pipeline steps smart enough to skip the step if it
++is not relevant.  This is as simple as::
++
++    def my_custom_step(strategy, backend, request, details, *args, **kwargs):
++        if backend_name != 'my_custom_backend':
++            return
++        # otherwise, do the special steps for your custom backend
++
++Interrupting the Pipeline (and communicating with views)
++---------------------------------------------------------
++
++Let's say you want to add a custom step in the pipeline -- you want the user
++to establish a password so that they can come directly to your site in the
++future.  We can do that with the @partial decorator, which tells the pipeline
++to keep track of where it is so that it can be restarted.
++
++The first thing we need to do is set up a way for our views to communicate with
++the pipeline. That is done by adding a value to the settings file to tell
++us which values should be passed back and forth between the Django session
++and the pipeline::
++
++    SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ['local_password',]
++
++In our pipeline code, we would have::
++
++    from django.shortcuts import redirect
++    from django.contrib.auth.models import User
++    from social.pipeline.partial import partial
++
++    # partial says "we may interrupt, but we will come back here again"
++    @partial
++    def collect_password(strategy, backend, request, details, *args, **kwargs):
++        # request['local_password'] is set by the pipeline infrastructure
++        # because it exists in FIELDS_STORED_IN_SESSION
++        if not request.get('local_password', None):
++
++            # if we return something besides a dict or None, then that is
++            # returned to the user -- in this case we will redirect to a
++            # view that can be used to get a password
++            return redirect("myapp.views.collect_password")
++
++        # grab the user object from the database (remember that they may
++        # not be logged in yet) and set their password.  (Assumes that the
++        # email address was captured in an earlier step.)
++        user = User.objects.get(email=kwargs['email'])
++        user.set_password(request['local_password'])
++        user.save()
++
++        # continue the pipeline
++        return
++
++In our view code, we would have something like::
++
++    class PasswordForm(forms.Form):
++        secret_word = forms.CharField(max_length=10)
++
++    def get_user_password(request):
++        if request.method == 'POST':
++            form = PasswordForm(request.POST)
++            if form.is_valid():
++                # because of FIELDS_STORED_IN_SESSION, this will get copied
++                # to the request dictionary when the pipeline is resumed
++                request.session['local_password'] = form.cleaned_data['secret_word']
++
++                # once we have the password stashed in the session, we can
++                # tell the pipeline to resume by using the "complete" endpoint
++                return redirect(reverse('social:complete', args=("backend_name,")))
++        else:
++            form = PasswordForm()
++
++        return render(request, "password_form.html")
++
++Note that the ``social:complete`` will re-enter the pipeline with the same
++function that interrupted it (in this case, collect_password).
+--- /dev/null
++++ b/docs/exceptions.rst
+@@ -0,0 +1,55 @@
++Exceptions
++==========
++
++This set of exceptions were introduced to describe the situations a bit more
++than just the ``ValueError`` usually raised.
++
++``SocialAuthBaseException``
++    Base class for all social auth exceptions.
++
++``AuthException``
++    Base exception class for authentication process errors.
++
++``AuthFailed``
++    Authentication failed for some reason.
++
++``AuthCanceled``
++    Authentication was canceled by the user.
++
++``AuthUnknownError``
++    An unknown error stoped the authentication process.
++
++``AuthTokenError``
++    Unauthorized or access token error, it was invalid, impossible to
++    authenticate or user removed permissions to it.
++
++``AuthMissingParameter``
++    A needed parameter to continue the process was missing, usually raised by
++    the services that need some POST data like myOpenID.
++
++``AuthAlreadyAssociated``
++    A different user has already associated the social account that the current
++    user is trying to associate.
++
++``WrongBackend``
++    Raised when the backend given in the URLs is invalid (not enabled or
++    registered).
++
++``NotAllowedToDisconnect``
++    Raised on disconnect action when it's not safe for the user to disconnect
++    the social account, probably because the user lacks a password or another
++    social account.
++
++``AuthStateMissing``
++    The state parameter is missing from the server response.
++
++``AuthStateForbidden``
++    The state parameter returned by the server is not the one sent.
++
++``AuthTokenRevoked``
++    Raised when the user revoked the access_token in the provider.
++
++``AuthUnreachableProvider``
++    Raised when server couldn't communicate with backend.
++
++These are a subclass of ``ValueError`` to keep backward compatibility.
+--- /dev/null
++++ b/docs/index.rst
+@@ -0,0 +1,46 @@
++Welcome to Python Social Auth's documentation!
++==============================================
++
++Python Social Auth aims to be an easy to setup social authentication and
++authorization mechanism for Python projects supporting protocols like OAuth (1
++and 2), OpenId and others.
++
++The initial codebase is derived from django-social-auth_ with the idea of
++generalizing the process to suit the different frameworks around, providing
++the needed tools to bring support to new frameworks.
++
++django-social-auth_ itself was a product of modified code from
++django-twitter-oauth_ and django-openid-auth_ projects.
++
++
++Contents:
++
++.. toctree::
++   :maxdepth: 2
++
++   intro
++   installing
++   configuration/index
++   pipeline
++   strategies
++   storage
++   exceptions
++   backends/index
++   developer_intro
++   logging_out
++   tests
++   use_cases
++   thanks
++   copyright
++
++
++Indices and Tables
++==================
++
++* :ref:`genindex`
++* :ref:`modindex`
++* :ref:`search`
++
++.. _django-social-auth: http://github.com/omab/django-social-auth
++.. _django-twitter-oauth: https://github.com/henriklied/django-twitter-oauth
++.. _django-openid-auth: https://launchpad.net/django-openid-auth
+--- /dev/null
++++ b/docs/installing.rst
+@@ -0,0 +1,58 @@
++Installation
++============
++
++Dependencies
++------------
++
++Dependencies that **must** be met to use the application:
++
++- OpenId_ support depends on python-openid_
++
++- OAuth_ support depends on requests-oauthlib_
++
++- Several backends demands application registration on their corresponding
++  sites and other dependencies like sqlalchemy_ on Flask and Webpy.
++
++
++Get a copy
++----------
++
++From pypi_::
++
++    $ pip install python-social-auth
++
++Or::
++
++    $ easy_install python-social-auth
++
++Or clone from github_::
++
++    $ git clone git://github.com/omab/python-social-auth.git
++
++And add social to ``PYTHONPATH``::
++
++    $ export PYTHONPATH=$PYTHONPATH:$(pwd)/python-social-auth/
++
++Or::
++
++    $ cd python-social-auth
++    $ sudo python setup.py install
++
++
++.. _OpenId: http://openid.net/
++.. _OAuth: http://oauth.net/
++.. _pypi: http://pypi.python.org/pypi/python-social-auth/
++.. _github: https://github.com/omab/python-social-auth
++.. _python-openid: http://pypi.python.org/pypi/python-openid/
++.. _requests-oauthlib: https://requests-oauthlib.readthedocs.org/
++.. _sqlalchemy: http://www.sqlalchemy.org/
++
++Upgrading
++---------
++
++Django with South
++~~~~~~~~~~~~~~~~~
++
++Upgrading from 0.1 to 0.2 is likely to cause problems trying to apply a migration when the tables already exist. In this case a fake migration needs to be applied:
++
++$ python manage.py migrate --fake default
+--- /dev/null
++++ b/docs/intro.rst
+@@ -0,0 +1,183 @@
++Introduction
++============
++
++Python Social Auth aims to be an easy to setup social authentication and
++authorization mechanism for Python projects supporting protocols like OAuth_ (1
++and 2), OpenId_ and others.
++
++
++Features
++--------
++
++This application provides user registration and login using social sites
++credentials, here are some features, probably not a full list yet.
++
++
++Supported frameworks
++********************
++
++Multiple frameworks support:
++
++    * Django_
++    * Flask_
++    * Pyramid_
++    * Webpy_
++    * Tornado_
++
++More frameworks can be added easily (and should be even easier in the future
++once the code matures).
++
++
++Auth providers
++**************
++
++Several supported service by simple backends definition (easy to add new ones
++or extend current one):
++
++    * Angel_ OAuth2
++    * Beats_ OAuth2
++    * Behance_ OAuth2
++    * Bitbucket_ OAuth1
++    * Box_ OAuth2
++    * Dailymotion_ OAuth2
++    * Deezer_ OAuth2
++    * Disqus_ OAuth2
++    * Douban_ OAuth1 and OAuth2
++    * Dropbox_ OAuth1
++    * Evernote_ OAuth1
++    * Facebook_ OAuth2 and OAuth2 for Applications
++    * Fitbit_ OAuth2 and OAuth1
++    * Flickr_ OAuth1
++    * Foursquare_ OAuth2
++    * `Google App Engine`_ Auth
++    * Github_ OAuth2
++    * Google_ OAuth1, OAuth2 and OpenId
++    * Instagram_ OAuth2
++    * Kakao_ OAuth2
++    * Linkedin_ OAuth1
++    * Live_ OAuth2
++    * Livejournal_ OpenId
++    * Mailru_ OAuth2
++    * MineID_ OAuth2
++    * Mixcloud_ OAuth2
++    * `Mozilla Persona`_
++    * NaszaKlasa_ OAuth2
++    * `NGPVAN ActionID`_ OpenId
++    * Odnoklassniki_ OAuth2 and Application Auth
++    * OpenId_
++    * Podio_ OAuth2
++    * Pinterest_ OAuth2
++    * Rdio_ OAuth1 and OAuth2
++    * Readability_ OAuth1
++    * Shopify_ OAuth2
++    * Skyrock_ OAuth1
++    * Soundcloud_ OAuth2
++    * Spotify_ OAuth2
++    * ThisIsMyJam_ OAuth1
++    * Stackoverflow_ OAuth2
++    * Steam_ OpenId
++    * Stocktwits_ OAuth2
++    * Stripe_ OAuth2
++    * Tripit_ OAuth1
++    * Tumblr_ OAuth1
++    * Twilio_ Auth
++    * Twitch_ OAuth2
++    * Twitter_ OAuth1
++    * Upwork_ OAuth1
++    * Vimeo_ OAuth1
++    * VK.com_ OpenAPI, OAuth2 and OAuth2 for Applications
++    * Weibo_ OAuth2
++    * Wunderlist_ OAuth2
++    * Xing_ OAuth1
++    * Yahoo_ OpenId and OAuth1
++    * Yammer_ OAuth2
++    * Yandex_ OAuth1, OAuth2 and OpenId
++
++
++User data
++*********
++
++Basic user data population, to allow custom fields values from providers
++response.
++
++
++Social accounts association
++***************************
++
++Multiple social accounts can be associated to a single user.
++
++
++Authentication and disconnection processing
++*******************************************
++
++Extensible pipeline to handle authentication, association and disconnection
++mechanism in ways that suits your project. Check `Authentication Pipeline`_
++section.
++
++
++.. _OpenId: http://openid.net/
++.. _OAuth: http://oauth.net/
++.. _myOpenID: https://www.myopenid.com/
++.. _Angel: https://angel.co
++.. _Beats: https://www.beats.com
++.. _Behance: https://www.behance.net
++.. _Bitbucket: https://bitbucket.org
++.. _Box: https://www.box.com
++.. _Dailymotion: https://dailymotion.com
++.. _Deezer: https://www.deezer.com
++.. _Disqus: https://disqus.com
++.. _Douban: http://www.douban.com
++.. _Dropbox: https://dropbox.com
++.. _Evernote: https://www.evernote.com
++.. _Facebook: https://www.facebook.com
++.. _Fitbit: https://fitbit.com
++.. _Flickr: http://www.flickr.com
++.. _Foursquare: https://foursquare.com
++.. _Google App Engine: https://developers.google.com/appengine/
++.. _Github: https://github.com
++.. _Google: http://google.com
++.. _Instagram: https://instagram.com
++.. _Kakao: https://kakao.com
++.. _Linkedin: https://www.linkedin.com
++.. _Live: https://www.live.com
++.. _Livejournal: http://livejournal.com
++.. _Mailru: https://mail.ru
++.. _MineID: https://www.mineid.org
++.. _Mixcloud: https://www.mixcloud.com
++.. _Mozilla Persona: http://www.mozilla.org/persona/
++.. _NaszaKlasa: https://developers.nk.pl/
++.. _NGPVAN ActionID: http://developers.ngpvan.com/action-id
++.. _Odnoklassniki: http://www.odnoklassniki.ru
++.. _Podio: https://podio.com
++.. _Shopify: http://shopify.com
++.. _Skyrock: https://skyrock.com
++.. _Soundcloud: https://soundcloud.com
++.. _Spotify: https://www.spotify.com
++.. _ThisIsMyJam: https://thisismyjam.com
++.. _Stocktwits: https://stocktwits.com
++.. _Stripe: https://stripe.com
++.. _Tripit: https://www.tripit.com
++.. _Twilio: https://www.twilio.com
++.. _Twitch: http://www.twitch.tv/
++.. _Twitter: http://twitter.com
++.. _VK.com: http://vk.com
++.. _Weibo: http://weibo.com
++.. _Wunderlist: http://wunderlist.com
++.. _Xing: https://www.xing.com
++.. _Yahoo: http://yahoo.com
++.. _Yammer: https://www.yammer.com
++.. _Yandex: https://yandex.ru
++.. _Pinterest: https://www.pinterest.com
++.. _Readability: http://www.readability.com/
++.. _Stackoverflow: http://stackoverflow.com/
++.. _Steam: http://steamcommunity.com/
++.. _Rdio: https://www.rdio.com
++.. _Vimeo: https://vimeo.com/
++.. _Tumblr: http://www.tumblr.com/
++.. _Django: https://github.com/omab/python-social-auth/tree/master/social/apps/django_app
++.. _Flask: https://github.com/omab/python-social-auth/tree/master/social/apps/flask_app
++.. _Pyramid: http://www.pylonsproject.org/projects/pyramid/about
++.. _Webpy: https://github.com/omab/python-social-auth/tree/master/social/apps/webpy_app
++.. _Tornado: http://www.tornadoweb.org/
++.. _Authentication Pipeline: pipeline.html
++.. _Upwork: https://www.upwork.com
+--- /dev/null
++++ b/docs/logging_out.rst
+@@ -0,0 +1,25 @@
++Disconnect and Logging Out
++==========================
++
++It's a common misconception that the ``disconnect`` action is the same as
++logging the user out, but this is not the case.
++
++``Disconnect`` is the way that your users can ask your project to "forget about
++my account". This implies removing the ``UserSocialAuth`` instance that was
++created, this also implies that the user won't be able to login back into your
++site with the social account. Instead the action will be a signup, a new user
++instance will be created, not related to the previous one.
++
++Logging out is just a way to say "forget my current session", and usually
++implies removing cookies, invalidating a session hash, etc. The many frameworks
++have their own ways to logout an account (Django has ``django.contrib.auth.logout``),
++``flask-login`` has it's own way too with `logout_user()`_.
++
++Since disconnecting a social account means that the user won't be able to log
++back in with that social provider into the same user, python-social-auth will
++check that the user account is in a valid state for disconnection (it has at
++least one more social account associated, or a password, etc). This behavior
++can be overridden by changing the `Disconnection Pipeline`_.
++
++.. _logout_user(): https://github.com/maxcountryman/flask-login/blob/a96de342eae560deec008a02179f593c3799b3ba/flask_login.py#L718-L739
++.. _Disconnection Pipeline: pipeline.html#disconnection-pipeline
+--- /dev/null
++++ b/docs/pipeline.rst
+@@ -0,0 +1,348 @@
++Pipeline
++========
++
++python-social-auth_ uses an extendible pipeline mechanism where developers can
++introduce their functions during the authentication, association and
++disconnection flows.
++
++The functions will receive a variable set of arguments related to the current
++process, common arguments are the current ``strategy``, ``user`` (if any) and
++``request``. It's recommended that all the function also define an ``**kwargs``
++in the parameters to avoid errors for unexpected arguments.
++
++Each pipeline entry can return a ``dict`` or ``None``, any other type of return
++value is treated as a response instance and returned directly to the client,
++check *Partial Pipeline* below for details.
++
++If a ``dict`` is returned, the value in the set will be merged into the
++``kwargs`` argument for the next pipeline entry, ``None`` is taken as if ``{}``
++was returned.
++
++
++Authentication Pipeline
++-----------------------
++
++The final process of the authentication workflow is handled by an operations
++pipeline where custom functions can be added or default items can be removed to
++provide a custom behavior. The default pipeline is a mechanism that creates
++user instances and gathers basic data from providers.
++
++The default pipeline is composed by::
++
++    (
++        # Get the information we can about the user and return it in a simple
++        # format to create the user instance later. On some cases the details are
++        # already part of the auth response from the provider, but sometimes this
++        # could hit a provider API.
++        'social.pipeline.social_auth.social_details',
++
++        # Get the social uid from whichever service we're authing thru. The uid is
++        # the unique identifier of the given user in the provider.
++        'social.pipeline.social_auth.social_uid',
++
++        # Verifies that the current auth process is valid within the current
++        # project, this is where emails and domains whitelists are applied (if
++        # defined).
++        'social.pipeline.social_auth.auth_allowed',
++
++        # Checks if the current social-account is already associated in the site.
++        'social.pipeline.social_auth.social_user',
++
++        # Make up a username for this person, appends a random string at the end if
++        # there's any collision.
++        'social.pipeline.user.get_username',
++
++        # Send a validation email to the user to verify its email address.
++        # Disabled by default.
++        # 'social.pipeline.mail.mail_validation',
++
++        # Associates the current social details with another user account with
++        # a similar email address. Disabled by default.
++        # 'social.pipeline.social_auth.associate_by_email',
++
++        # Create a user account if we haven't found one yet.
++        'social.pipeline.user.create_user',
++
++        # Create the record that associates the social account with the user.
++        'social.pipeline.social_auth.associate_user',
++
++        # Populate the extra_data field in the social record with the values
++        # specified by settings (and the default ones like access_token, etc).
++        'social.pipeline.social_auth.load_extra_data',
++
++        # Update the user record with any changed info from the auth service.
++        'social.pipeline.user.user_details',
++    )
++
++
++It's possible to override it by defining the setting ``SOCIAL_AUTH_PIPELINE``.
++For example, a pipeline that won't create users, just accept already registered
++ones would look like this::
++
++    SOCIAL_AUTH_PIPELINE = (
++        'social.pipeline.social_auth.social_details',
++        'social.pipeline.social_auth.social_uid',
++        'social.pipeline.social_auth.auth_allowed',
++        'social.pipeline.social_auth.social_user',
++        'social.pipeline.social_auth.associate_user',
++        'social.pipeline.social_auth.load_extra_data',
++        'social.pipeline.user.user_details',
++    )
++
++Note that this assumes the user is already authenticated, and thus the ``user`` key
++in the dict is populated. In cases where the authentication is purely external, a
++pipeline method must be provided that populates the ``user`` key. Example::
++
++
++    SOCIAL_AUTH_PIPELINE = (
++        'myapp.pipeline.load_user',
++        'social.pipeline.social_auth.social_user',
++        'social.pipeline.social_auth.associate_user',
++        'social.pipeline.social_auth.load_extra_data',
++        'social.pipeline.user.user_details',
++    )
++
++Each pipeline function will receive the following parameters:
++    * Current strategy (which gives access to current store, backend and request)
++    * User ID given by authentication provider
++    * User details given by authentication provider
++    * ``is_new`` flag (initialized as ``False``)
++    * Any arguments passed to ``auth_complete`` backend method, default views
++      pass these arguments:
++      
++      * current logged in user (if it's logged in, otherwise ``None``)
++      * current request
++
++
++Disconnection Pipeline
++----------------------
++
++Like the authentication pipeline, it's possible to define a disconnection
++pipeline if needed.
++
++For example, this can be useful on sites where a user that disconnects all the
++related social account is required to fill a password to ensure the
++authentication process in the future. This can be accomplished by overriding
++the default disconnection pipeline and setup a function that checks if the user
++has a password, in case it doesn't a redirect to a fill-your-password form can
++be returned and later continue the disconnection process, take into account
++that disconnection ensures the POST method by default, a simple method to
++ensure this, is to make your form POST to ``/disconnect/`` and set the needed
++password in your pipeline function. Check *Partial Pipeline* below.
++
++In order to override the disconnection pipeline, just define the setting::
++
++    SOCIAL_AUTH_DISCONNECT_PIPELINE = (
++        # Verifies that the social association can be disconnected from the current
++        # user (ensure that the user login mechanism is not compromised by this
++        # disconnection).
++        'social.pipeline.disconnect.allowed_to_disconnect',
++
++        # Collects the social associations to disconnect.
++        'social.pipeline.disconnect.get_entries',
++
++        # Revoke any access_token when possible.
++        'social.pipeline.disconnect.revoke_tokens',
++
++        # Removes the social associations.
++        'social.pipeline.disconnect.disconnect',
++    )
++
++
++Partial Pipeline
++----------------
++
++It's possible to cut the pipeline process to return to the user asking for more
++data and resume the process later. To accomplish this decorate the function
++that will cut the process with the ``@partial`` decorator located at
++``social/pipeline/partial.py``.
++
++The old ``social.pipeline.partial.save_status_to_session`` is now deprecated.
++
++When it's time to resume the process just redirect the user to ``/complete/<backend>/``
++or ``/disconnect/<backend>/`` view. The pipeline will resume in the same
++function that cut the process.
++
++``@partial`` and ``save_status_to_session`` stores needed data into user session
++under the key ``partial_pipeline``. To get the backend in order to redirect to
++any social view, just do::
++
++    backend = session['partial_pipeline']['backend']
++
++Check the `example applications`_ to check a basic usage.
++
++
++Email validation
++----------------
++
++There's a pipeline to validate email addresses, but it relies a lot on your
++project.
++
++The pipeline is at ``social.pipeline.mail.mail_validation`` and it's a partial
++pipeline, it will return a redirect to a URL that you can use to tell the
++users that an email validation was sent to them. If you want to mention the
++email address you can get it from the session under the key ``email_validation_address``.
++
++In order to send the validation python-social-auth_ needs a function that will
++take care of it, this function is defined by the developer with the setting
++``SOCIAL_AUTH_EMAIL_VALIDATION_FUNCTION``. It should be an import path. This
++function should take three arguments ``strategy``, ``backend`` and ``code``.
++``code`` is a model instance used to validate the email address, it contains
++three fields:
++
++``code = '...'``
++    Holds an ``uuid.uuid4()`` value and it's the code used to identify the
++    validation process.
++
++``email = '...'``
++    Email address trying to be validate.
++
++``verified = True / False``
++    Flag marking if the email was verified or not.
++
++You should use the code in this instance to build the link for email
++validation which should go to ``/complete/email?verification_code=<code here>``. If you are using
++Django, you can do it with::
++
++    from django.core.urlresolvers import reverse
++    url = strategy.build_absolute_uri(
++        reverse('social:complete', args=(strategy.backend_name,))
++    ) + '?verification_code=' + code.code
++
++On Flask::
++
++    from flask import url_for
++    url = url_for('social.complete', backend=strategy.backend_name,
++                  _external=True) + '?verification_code=' + code
++
++This pipeline can be used globally with any backend if this setting is
++defined::
++
++    SOCIAL_AUTH_FORCE_EMAIL_VALIDATION = True
++
++Or individually by defining the setting per backend basis like
++``SOCIAL_AUTH_TWITTER_FORCE_EMAIL_VALIDATION = True``.
++
++
++Extending the Pipeline
++======================
++
++The main purpose of the pipeline (either creation or deletion pipelines) is to
++allow extensibility for developers. You can jump in the middle of it, do
++changes to the data, create other models instances, ask users for extra data,
++or even halt the whole process.
++
++Extending the pipeline implies:
++
++    1. Writing a function
++    2. Locating the function in an accessible path 
++       (accessible in the way that it can be imported)
++    3. Overriding the default pipeline definition with one that includes
++       newly created function.
++
++The part of writing the function is quite simple. However please be careful
++when placing your function in the pipeline definition, because order
++does matter in this case! Ordering of functions in ``SOCIAL_AUTH_PIPELINE``
++will determine the value of arguments that each function will receive. 
++For example, adding your function after ``social.pipeline.user.create_user``
++ensures that your function will get the user instance (created or already existent)
++instead of a ``None`` value.
++
++The pipeline functions will get quite a lot of arguments, ranging from the
++backend in use, different model instances, server requests and provider
++responses. To enumerate a few:
++
++``strategy``
++    The current strategy instance.
++
++``backend``
++    The current backend instance.
++
++``uid``
++    User ID in the provider, this ``uid`` should identify the user in the
++    current provider.
++
++``response = {} or object()``
++    The server user-details response, it depends on the protocol in use (and
++    sometimes the provider implementation of such protocol), but usually it's
++    just a ``dict`` with the user profile details in such provider. Lots of
++    information related to the user is provided here, sometimes the ``scope``
++    will increase the amount of information in this response on OAuth
++    providers.
++
++``details = {}``
++    Basic user details generated by the backend, used to create/update the user
++    model details (this ``dict`` will contain values like ``username``,
++    ``email``, ``first_name``, ``last_name`` and ``fullname``).
++
++``user = None``
++    The user instance (or ``None`` if it wasn't created or retrieved from the
++    database yet).
++
++``social = None``
++    This is the associated ``UserSocialAuth`` instance for the given user (or
++    ``None`` if it wasn't created or retrieved from the DB yet).
++
++Usually when writing your custom pipeline function, you just want to get some
++values from the ``response`` parameter. But you can do even more, like call
++other APIs endpoints to retrieve even more details about the user, store them
++on some other place, etc.
++
++Here's an example of a simple pipeline function that will create a ``Profile``
++class instance, related to the current user. This profile will store some simple details
++returned by the provider (``Facebook`` in this example). The usual Facebook
++``response`` looks like this::
++
++    {
++        'username': 'foobar',
++        'access_token': 'CAAD...',
++        'first_name': 'Foo',
++        'last_name': 'Bar',
++        'verified': True,
++        'name': 'Foo Bar',
++        'locale': 'en_US',
++        'gender': 'male',
++        'expires': '5183999',
++        'email': 'foo at bar.com',
++        'updated_time': '2014-01-14T15:58:35+0000',
++        'link': 'https://www.facebook.com/foobar',
++        'timezone': -3,
++        'id': '100000126636010',
++    }
++
++Let's say we are interested in storing the user profile link, the gender and
++the timezone in our ``Profile`` model::
++
++    def save_profile(backend, user, response, *args, **kwargs):
++        if backend.name == 'facebook':
++            profile = user.get_profile()
++            if profile is None:
++                profile = Profile(user_id=user.id)
++            profile.gender = response.get('gender')
++            profile.link = response.get('link')
++            profile.timezone = response.get('timezone')
++            profile.save()
++
++Now all that's needed is to tell ``python-social-auth`` to use our function in
++the pipeline. Since the function uses user instance, we need to put it after
++``social.pipeline.user.create_user``::
++
++    SOCIAL_AUTH_PIPELINE = (
++        'social.pipeline.social_auth.social_details',
++        'social.pipeline.social_auth.social_uid',
++        'social.pipeline.social_auth.auth_allowed',
++        'social.pipeline.social_auth.social_user',
++        'social.pipeline.user.get_username',
++        'social.pipeline.user.create_user',
++        'path.to.save_profile',  # <--- set the path to the function
++        'social.pipeline.social_auth.associate_user',
++        'social.pipeline.social_auth.load_extra_data',
++        'social.pipeline.user.user_details',
++    )
++
++So far the function we created returns ``None``, which is taken as if ``{}`` was returned.
++If you want the ``profile`` object to be available to the next function in the
++pipeline, all you need to do is return ``{'profile': profile}``.
++
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _example applications: https://github.com/omab/python-social-auth/tree/master/examples
+--- /dev/null
++++ b/docs/storage.rst
+@@ -0,0 +1,200 @@
++Storage
++=======
++
++Different frameworks support different ORMs, Storage solves the different
++interfaces moving the common API to mixins classes. These mixins are used on
++apps when defining the different models used by ``python-social-auth``.
++
++
++Social User
++-----------
++
++This model associates a social account data with a user in the system, it
++contains the provider name and user ID (``uid``) which should identify the
++social account in the remote provider, plus some extra data (``extra_data``)
++which is JSON encoded field with extra information from the provider (usually
++avatars and similar).
++
++When implementing this model, it must inherits from UserMixin_ and extend the
++needed methods:
++
++* Username::
++
++    @classmethod
++    def get_username(cls, user):
++        """Return the username for given user"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def username_max_length(cls):
++        """Return the max length for username"""
++        raise NotImplementedError('Implement in subclass')
++
++* User model::
++
++    @classmethod
++    def user_model(cls):
++        """Return the user model"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def changed(cls, user):
++        """The given user instance is ready to be saved"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def user_exists(cls, username):
++        """
++        Return True/False if a User instance exists with the given arguments.
++        Arguments are directly passed to filter() manager method.
++        """
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def create_user(cls, username, email=None):
++        """Create a user with given username and (optional) email"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def get_user(cls, pk):
++        """Return user instance for given id"""
++        raise NotImplementedError('Implement in subclass')
++
++* Social user::
++
++    @classmethod
++    def get_social_auth(cls, provider, uid):
++        """Return UserSocialAuth for given provider and uid"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def get_social_auth_for_user(cls, user):
++        """Return all the UserSocialAuth instances for given user"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def create_social_auth(cls, user, uid, provider):
++        """Create a UserSocialAuth instance for given user"""
++        raise NotImplementedError('Implement in subclass')
++
++* Social disconnection::
++
++    @classmethod
++    def allowed_to_disconnect(cls, user, backend_name, association_id=None):
++        """Return if it's safe to disconnect the social account for the
++        given user"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def disconnect(cls, name, user, association_id=None):
++        """Disconnect the social account for the given user"""
++        raise NotImplementedError('Implement in subclass')
++
++
++Nonce
++-----
++
++This is a helper class for OpenId mechanism, it stores a one-use number,
++shouldn't be used by the project since it's for internal use only.
++
++When implementing this model, it must inherits from NonceMixin_, and override
++the needed method::
++
++    @classmethod
++    def use(cls, server_url, timestamp, salt):
++        """Create a Nonce instance"""
++        raise NotImplementedError('Implement in subclass')
++
++
++Association
++-----------
++
++Another OpenId helper class, it stores basic data to keep the OpenId
++association. Like Nonce_ this is for internal use only.
++
++When implementing this model, it must inherits from AssociationMixin_, and
++override the needed methods::
++
++    @classmethod
++    def store(cls, server_url, association):
++        """Create an Association instance"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def get(cls, *args, **kwargs):
++        """Get an Association instance"""
++        raise NotImplementedError('Implement in subclass')
++
++    @classmethod
++    def remove(cls, ids_to_delete):
++        """Remove an Association instance"""
++        raise NotImplementedError('Implement in subclass')
++
++
++Validation code
++---------------
++
++This class is used to keep track of email validations codes following the usual
++email validation mechanism of sending an email to the user with a unique code.
++This model is used by the partial pipeline ``social.pipeline.mail.mail_validation``.
++Check the docs at *Email validation* in `pipeline docs`_.
++
++When implementing the model for your framework only one method needs to be
++overridden::
++
++    @classmethod
++    def get_code(cls, code):
++        """Return the Code instance with the given code value"""
++        raise NotImplementedError('Implement in subclass')
++
++
++Storage interface
++-----------------
++
++There's a helper class used by strategies to hide the real models names under
++a common API, an instance of this class is used by strategies to access the
++storage modules.
++
++When implementing this class it must inherits from BaseStorage_, add the needed
++models references and implement the needed method::
++
++    class StorageImplementation(BaseStorage):
++        user = UserModel
++        nonce = NonceModel
++        association = AssociationModel
++        code = CodeModel
++
++        @classmethod
++        def is_integrity_error(cls, exception):
++            """Check if given exception flags an integrity error in the DB"""
++            raise NotImplementedError('Implement in subclass')
++
++
++SQLAlchemy and Django mixins
++----------------------------
++
++Currently there are partial implementations of mixins for `SQLAlchemy ORM`_ and
++`Django ORM`_ with common code used later on current implemented applications.
++
++**When using `SQLAlchemy ORM`_ and ``ZopeTransactionExtension``, it's
++recommended to use the transaction_ application to handle them.**
++
++Models Examples
++---------------
++
++Check for current implementations for `Django App`_, `Flask App`_, `Pyramid
++App`_, and `Webpy App`_ for examples of implementations.
++
++
++.. _UserMixin: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L15
++.. _NonceMixin: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L149
++.. _AssociationMixin: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L161
++.. _BaseStorage: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L201
++.. _SQLAlchemy ORM: https://github.com/omab/python-social-auth/blob/master/social/storage/sqlalchemy_orm.py
++.. _Django ORM: https://github.com/omab/python-social-auth/blob/master/social/storage/django_orm.py
++.. _Django App: https://github.com/omab/python-social-auth/blob/master/social/apps/django_app/default/models.py
++.. _Flask App: https://github.com/omab/python-social-auth/blob/master/social/apps/flask_app/models.py
++.. _Pyramid App: https://github.com/omab/python-social-auth/blob/master/social/apps/pyramid_app/models.py
++.. _Webpy App: https://github.com/omab/python-social-auth/blob/master/social/apps/webpy_app/models.py
++.. _pipeline docs: pipeline.html#email-validation
++.. _transaction: https://pypi.python.org/pypi/transaction
+--- /dev/null
++++ b/docs/strategies.rst
+@@ -0,0 +1,77 @@
++Strategies
++==========
++
++Different strategies are defined to encapsulate the different frameworks
++capabilities under a common API to reuse as much code as possible.
++
++
++Description
++-----------
++
++A strategy's responsibility is to provide access to:
++
++    * Request data and host information and URI building
++    * Session access
++    * Project settings
++    * Response types (HTML and redirects)
++    * HTML rendering
++
++Different frameworks implement these features on different ways, thus the need
++for these interfaces.
++
++
++Implementing a new Strategy
++---------------------------
++
++The following methods must be defined on strategies sub-classes.
++
++Request::
++
++    def request_data(self):
++        """Return current request data (POST or GET)"""
++        raise NotImplementedError('Implement in subclass')
++
++    def request_host(self):
++        """Return current host value"""
++        raise NotImplementedError('Implement in subclass')
++
++    def build_absolute_uri(self, path=None):
++        """Build absolute URI with given (optional) path"""
++        raise NotImplementedError('Implement in subclass')
++
++
++Session::
++
++    def session_get(self, name):
++        """Return session value for given key"""
++        raise NotImplementedError('Implement in subclass')
++
++    def session_set(self, name, value):
++        """Set session value for given key"""
++        raise NotImplementedError('Implement in subclass')
++
++    def session_pop(self, name):
++        """Pop session value for given key"""
++        raise NotImplementedError('Implement in subclass')
++
++
++Settings::
++
++    def get_setting(self, name):
++        """Return value for given setting name"""
++        raise NotImplementedError('Implement in subclass')
++
++
++Responses::
++
++    def html(self, content):
++        """Return HTTP response with given content"""
++        raise NotImplementedError('Implement in subclass')
++
++    def redirect(self, url):
++        """Return a response redirect to the given URL"""
++        raise NotImplementedError('Implement in subclass')
++
++    def render_html(self, tpl=None, html=None, context=None):
++        """Render given template or raw html with given context"""
++        raise NotImplementedError('Implement in subclass')
+--- /dev/null
++++ b/docs/tests.rst
+@@ -0,0 +1,48 @@
++Testing python-social-auth
++==========================
++
++Testing the application is fair simple, just met the dependencies and run the
++testing suite.
++
++The testing suite uses HTTPretty_ to mock server responses, it's not a live
++test against the providers API, to do it that way, a browser and a tool like
++Selenium are needed, that's slow, prone to errors on some cases, and some of
++the application examples must be running to perform the testing. Plus real Key
++and Secret pairs, in the end it's a mess to test functionality which is the
++real point.
++
++By mocking the server responses, we can test the backends functionality (and
++other areas too) easily and quick.
++
++
++Installing dependencies
++-----------------------
++
++Go to the tests_ directory and install the dependencies listed in the
++requirements.txt_. Then run with ``nosetests`` command, or with the
++``run_tests.sh`` script.
++
++Tox
++---
++
++You can use tox_ to test compatibility against all supported Python versions:
++
++.. code-block:: bash
++
++    $ pip install tox  # if not present
++    $ tox
++
++
++Pending
++-------
++
++At the moment only OAuth1, OAuth2 and OpenId backends are being tested, and
++just login and partial pipeline features are covered by the test. There's still
++a lot to work on, like:
++
++    * Frameworks support
++
++.. _HTTPretty: https://github.com/gabrielfalcao/HTTPretty
++.. _tests: https://github.com/omab/python-social-auth/tree/master/tests
++.. _requirements.txt: https://github.com/omab/python-social-auth/blob/master/tests/requirements.txt
++.. _tox: http://tox.readthedocs.org/
+--- /dev/null
++++ b/docs/thanks.rst
+@@ -0,0 +1,219 @@
++Thanks
++======
++
++
++python-social-auth_ is the result of almost 3 years of development done on
++django-social-auth_ which is the result of my initial work and the thousands
++lines of code contributed by so many developers that took time to work on
++improvements, report bugs and hunt them down to propose a fix. So, here is
++a big list of users that helped to build this library (if somebody is missed
++let me know and I'll update the list):
++
++  * kjoconnor_
++  * krvss_
++  * estebistec_
++  * mrmch_
++  * uruz_
++  * maraujop_
++  * bacher09_
++  * dokterbob_
++  * hassek_
++  * andrusha_
++  * vicalloy_
++  * caioariede_
++  * danielgtaylor_
++  * stephenmcd_
++  * gugu_
++  * yrik_
++  * dhendo_
++  * yekibud_
++  * tmackenzie_
++  * LuanP_
++  * jezdez_
++  * serdardalgic_
++  * Jolmberg_
++  * ChrisCooper_
++  * marselester_
++  * eshellman_
++  * micrypt_
++  * revolunet_
++  * dasevilla_
++  * seansay_
++  * hepochen_
++  * gibuloto_
++  * crodjer_
++  * sidmitra_
++  * ryr_
++  * inve1_
++  * mback2k_
++  * hannesstruss_
++  * NorthIsUp_
++  * tonyxiao_
++  * dhepper_
++  * Troytft_
++  * gardaud_
++  * oinopion_
++  * gameguy43_
++  * vinigracindo_
++  * syabro_
++  * bashmish_
++  * ggreer_
++  * avillavi_
++  * r4vi_
++  * roderyc_
++  * daonb_
++  * slon7_
++  * JasonGiedymin_
++  * tymofij_
++  * Cassus_
++  * martey_
++  * t0m_
++  * johnthedebs_
++  * jammons_
++  * stefanw_
++  * maxgrosse_
++  * mattucf_
++  * tadeo_
++  * haxoza_
++  * bradbeattie_
++  * henward0_
++  * bernardokyotoku_
++  * czpython_
++  * glasscube42_
++  * assiotis_
++  * dbaxa_
++  * JasonSanford_
++  * originell_
++  * cihann_
++  * niftynei_
++  * mikesun_
++  * 1st_
++  * betonimig_
++  * ozexpert_
++  * stephenLee_
++  * julianvargasalvarez_
++  * youngrok_
++  * garrypolley_
++  * amirouche_
++  * fmoga_
++  * pydanny_
++  * pygeek_
++  * dgouldin_
++  * kotslon_
++  * kirkchris_
++  * barracel_
++  * sayar_
++  * kulbir_
++  * Morgul_
++  * spstpl_
++  * bluszcz_
++  * vbsteven_
++  * sbassi_
++  * aspcanada_
++  * browniebroke_
++
++
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _django-social-auth: https://github.com/omab/django-social-auth
++.. _kjoconnor: https://github.com/kjoconnor
++.. _krvss: https://github.com/krvss
++.. _estebistec: https://github.com/estebistec
++.. _mrmch: https://github.com/mrmch
++.. _uruz: https://github.com/uruz
++.. _maraujop: https://github.com/maraujop
++.. _bacher09: https://github.com/bacher09
++.. _dokterbob: https://github.com/dokterbob
++.. _hassek: https://github.com/hassek
++.. _andrusha: https://github.com/andrusha
++.. _vicalloy: https://github.com/vicalloy
++.. _caioariede: https://github.com/caioariede
++.. _danielgtaylor: https://github.com/danielgtaylor
++.. _stephenmcd: https://github.com/stephenmcd
++.. _gugu: https://github.com/gugu
++.. _yrik: https://github.com/yrik
++.. _dhendo: https://github.com/dhendo
++.. _yekibud: https://github.com/yekibud
++.. _tmackenzie: https://github.com/tmackenzie
++.. _LuanP: https://github.com/LuanP
++.. _jezdez: https://github.com/jezdez
++.. _serdardalgic: https://github.com/serdardalgic
++.. _Jolmberg: https://github.com/Jolmberg
++.. _ChrisCooper: https://github.com/ChrisCooper
++.. _marselester: https://github.com/marselester
++.. _eshellman: https://github.com/eshellman
++.. _micrypt: https://github.com/micrypt
++.. _revolunet: https://github.com/revolunet
++.. _dasevilla: https://github.com/dasevilla
++.. _seansay: https://github.com/seansay
++.. _hepochen: https://github.com/hepochen
++.. _gibuloto: https://github.com/gibuloto
++.. _crodjer: https://github.com/crodjer
++.. _sidmitra: https://github.com/sidmitra
++.. _ryr: https://github.com/ryr
++.. _inve1: https://github.com/inve1
++.. _mback2k: https://github.com/mback2k
++.. _hannesstruss: https://github.com/hannesstruss
++.. _NorthIsUp: https://github.com/NorthIsUp
++.. _tonyxiao: https://github.com/tonyxiao
++.. _dhepper: https://github.com/dhepper
++.. _Troytft: https://github.com/Troytft
++.. _gardaud: https://github.com/gardaud
++.. _oinopion: https://github.com/oinopion
++.. _gameguy43: https://github.com/gameguy43
++.. _vinigracindo: https://github.com/vinigracindo
++.. _syabro: https://github.com/syabro
++.. _bashmish: https://github.com/bashmish
++.. _ggreer: https://github.com/ggreer
++.. _avillavi: https://github.com/avillavi
++.. _r4vi: https://github.com/r4vi
++.. _roderyc: https://github.com/roderyc
++.. _daonb: https://github.com/daonb
++.. _slon7: https://github.com/slon7
++.. _JasonGiedymin: https://github.com/JasonGiedymin
++.. _tymofij: https://github.com/tymofij
++.. _Cassus: https://github.com/Cassus
++.. _martey: https://github.com/martey
++.. _t0m: https://github.com/t0m
++.. _johnthedebs: https://github.com/johnthedebs
++.. _jammons: https://github.com/jammons
++.. _stefanw: https://github.com/stefanw
++.. _maxgrosse: https://github.com/maxgrosse
++.. _mattucf: https://github.com/mattucf
++.. _tadeo: https://github.com/tadeo
++.. _haxoza: https://github.com/haxoza
++.. _bradbeattie: https://github.com/bradbeattie
++.. _henward0: https://github.com/henward0
++.. _bernardokyotoku: https://github.com/bernardokyotoku
++.. _czpython: https://github.com/czpython
++.. _glasscube42: https://github.com/glasscube42
++.. _assiotis: https://github.com/assiotis
++.. _dbaxa: https://github.com/dbaxa
++.. _JasonSanford: https://github.com/JasonSanford
++.. _originell: https://github.com/originell
++.. _cihann: https://github.com/cihann
++.. _niftynei: https://github.com/niftynei
++.. _mikesun: https://github.com/mikesun
++.. _1st: https://github.com/1st
++.. _betonimig: https://github.com/betonimig
++.. _ozexpert: https://github.com/ozexpert
++.. _stephenLee: https://github.com/stephenLee
++.. _julianvargasalvarez: https://github.com/julianvargasalvarez
++.. _youngrok: https://github.com/youngrok
++.. _garrypolley: https://github.com/garrypolley
++.. _amirouche: https://github.com/amirouche
++.. _fmoga: https://github.com/fmoga
++.. _pydanny: https://github.com/pydanny
++.. _pygeek: https://github.com/pygeek
++.. _dgouldin: https://github.com/dgouldin
++.. _kotslon: https://github.com/kotslon
++.. _kirkchris: https://github.com/kirkchris
++.. _barracel: https://github.com/barracel
++.. _sayar: https://github.com/sayar
++.. _kulbir: https://github.com/kulbir
++.. _Morgul: https://github.com/Morgul
++.. _spstpl: https://github.com/spstpl
++.. _bluszcz: https://github.com/bluszcz
++.. _vbsteven: https://github.com/vbsteven
++.. _sbassi: https://github.com/sbassi
++.. _aspcanada: https://github.com/aspcanada
++.. _browniebroke: https://github.com/browniebroke
+--- /dev/null
++++ b/docs/use_cases.rst
+@@ -0,0 +1,312 @@
++Use Cases
++=========
++
++Some miscellaneous options and use cases for python-social-auth_.
++
++
++Return the user to the original page
++------------------------------------
++
++There's a common scenario to return the user back to the original page from
++where they requested to login. For that purpose, the usual ``next`` query-string
++argument is used. The value of this parameter will be stored in the session and
++later used to redirect the user when login was successful.
++
++In order to use it, just define it with your link. For instance, when using
++Django::
++
++    <a href="{% url 'social:begin' 'facebook' %}?next={{ request.path }}">Login with Facebook</a>
++
++
++Pass custom GET/POST parameters and retrieve them on authentication
++-------------------------------------------------------------------
++
++In some cases, you might need to send data over the URL, and retrieve it while
++processing the after-effect. For example, for conditionally executing code in
++custom pipelines.
++
++In such cases, add it to ``FIELDS_STORED_IN_SESSION``.
++
++In your settings::
++
++    FIELDS_STORED_IN_SESSION = ['key']
++
++In template::
++
++    <a href="{% url 'social:begin' 'facebook' %}?key={{ value }}">Login with Facebook</a>
++
++In your custom pipeline, retrieve it using::
++
++    strategy.session_get('key')
++
++
++
++Retrieve Google+ Friends
++------------------------
++
++Google provides a `People API endpoint`_ to retrieve the people in your circles
++on Google+. In order to access that API first we need to define the needed
++scope::
++
++    SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
++        'https://www.googleapis.com/auth/plus.login'
++    ]
++
++Once we have the ``access token`` we can call the API like this::
++
++    import requests
++
++    user = User.objects.get(...)
++    social = user.social_auth.get(provider='google-oauth2')
++    response = requests.get(
++        'https://www.googleapis.com/plus/v1/people/me/people/visible',
++        params={'access_token': social.extra_data['access_token']}
++    )
++    friends = response.json()['items']
++
++
++Associate users by email
++------------------------
++
++Sometimes it's desirable that social accounts are automatically associated if
++the email already matches a user account.
++
++For example, if a user signed up with his Facebook account, then logged out and
++next time tries to use Google OAuth2 to login, it could be nice (if both social
++sites have the same email address configured) that the user gets into his
++initial account created by Facebook backend.
++
++This scenario is possible by enabling the ``associate_by_email`` pipeline
++function, like this::
++
++    SOCIAL_AUTH_PIPELINE = (
++        'social.pipeline.social_auth.social_details',
++        'social.pipeline.social_auth.social_uid',
++        'social.pipeline.social_auth.auth_allowed',
++        'social.pipeline.social_auth.social_user',
++        'social.pipeline.user.get_username',
++        'social.pipeline.social_auth.associate_by_email',  # <--- enable this one
++        'social.pipeline.user.create_user',
++        'social.pipeline.social_auth.associate_user',
++        'social.pipeline.social_auth.load_extra_data',
++        'social.pipeline.user.user_details',
++    )
++
++This feature is disabled by default because it's not 100% secure to automate
++this process with all the backends. Not all the providers will validate your
++email account and others users could take advantage of that.
++
++Take for instance User A registered in your site with the email
++``foo at bar.com``. Then a malicious user registers into another provider that
++doesn't validate his email with that same account. Finally this user will turn
++to your site (which supports that provider) and sign up to it, since the email
++is the same, the malicious user will take control over the User A account.
++
++
++Signup by OAuth access_token
++----------------------------
++
++It's a common scenario that mobile applications will use an SDK to signup
++a user within the app, but that signup won't be reflected by
++python-social-auth_ unless the corresponding database entries are created. In
++order to do so, it's possible to create a view / route that creates those
++entries by a given ``access_token``. Take the following code for instance (the
++code follows Django conventions, but versions for others frameworks can be
++implemented easily)::
++
++    from django.contrib.auth import login
++
++    from social.apps.django_app.utils import psa
++
++    # Define an URL entry to point to this view, call it passing the
++    # access_token parameter like ?access_token=<token>. The URL entry must
++    # contain the backend, like this:
++    #
++    #   url(r'^register-by-token/(?P<backend>[^/]+)/$',
++    #       'register_by_access_token')
++
++    @psa('social:complete')
++    def register_by_access_token(request, backend):
++        # This view expects an access_token GET parameter, if it's needed,
++        # request.backend and request.strategy will be loaded with the current
++        # backend and strategy.
++        token = request.GET.get('access_token')
++        user = request.backend.do_auth(request.GET.get('access_token'))
++        if user:
++            login(request, user)
++            return 'OK'
++        else:
++            return 'ERROR'
++
++The snippet above is quite simple, it doesn't return JSON and usually this call
++will be done by AJAX. It doesn't return the user information, but that's
++something that can be extended and filled to suit the project where it's going
++to be used.
++
++
++Multiple scopes per provider
++----------------------------
++
++At the moment python-social-auth_ doesn't provide a method to define multiple
++scopes for single backend, this is usually desired since it's recommended to
++ask the user for the minimum scope possible and increase the access when it's
++really needed. It's possible to add a new backend extending the original one to
++accomplish that behavior. There are two ways to do it.
++
++1. Overriding ``get_scope()`` method::
++
++    from social.backends.facebook import FacebookOAuth2
++
++
++    class CustomFacebookOAuth2(FacebookOauth2):
++        def get_scope(self):
++            scope = super(CustomFacebookOAuth2, self).get_scope()
++            if self.data.get('extrascope'):
++                scope = scope + [('foo', 'bar')]
++            return scope
++
++
++   This method is quite simple, it overrides the method that returns the scope
++   value in a backend (``get_scope()``) and adds extra values tot he list if it
++   was indicated by a parameter in the ``GET`` or ``POST`` data
++   (``self.data``).
++
++   Put this new backend in some place in your project and replace the original
++   ``FacebookOAuth2`` in ``AUTHENTICATION_BACKENDS`` with this new version.
++
++   When overriding this method, take into account that the default output the
++   base class for ``get_scope()`` is the raw value from the settings (whatever
++   they are defined), doing this will actually update the value in your
++   settings for all the users::
++
++    scope = super(CustomFacebookOAuth2, self).get_scope()
++    scope += ['foo', 'bar']
++
++   Instead do it like this::
++
++    scope = super(CustomFacebookOAuth2, self).get_scope()
++    scope = scope + ['foo', 'bar']
++
++2. It's possible to do the same by defining a second backend which extends from
++   the original but overrides the name, this will imply new URLs and also new
++   settings for the new backend (since the name is used to build the settings
++   names), it also implies a new application in the provider since not all
++   providers give you the option of defining multiple redirect URLs. To do it
++   just add a backend like::
++
++    from social.backends.facebook import FacebookOAuth2
++
++
++    class CustomFacebookOAuth2(FacebookOauth2):
++        name = 'facebook-custom'
++
++   Put this new backend in some place in your project keeping the original
++   ``FacebookOAuth2`` in ``AUTHENTICATION_BACKENDS``. Now a new set of URLs
++   will be functional::
++
++    /login/facebook-custom
++    /complete/facebook-custom
++    /disconnect/facebook-custom
++
++   And also a new set of settings::
++
++    SOCIAL_AUTH_FACEBOOK_CUSTOM_KEY = '...'
++    SOCIAL_AUTH_FACEBOOK_CUSTOM_SECRET = '...'
++    SOCIAL_AUTH_FACEBOOK_CUSTOM_SCOPE = [...]
++
++   When the extra permissions are needed, just redirect the user to
++   ``/login/facebook-custom`` and then get the social auth entry for this new
++   backend with ``user.social_auth.get(provider='facebook-custom')`` and use
++   the ``access_token`` in it.
++
++
++Enable a user to choose a username from his World of Warcraft characters
++------------------------------------------------------------------------
++
++If you want to register new users on your site via battle.net, you can enable
++these users to choose a username from their own World-of-Warcraft characters.
++To do this, use the ``battlenet-oauth2`` backend along with a small form to
++choose the username.
++
++The form is rendered via a partial pipeline item like this::
++
++    @partial
++    def pick_character_name(backend, details, response, is_new=False, *args, **kwargs):
++        if backend.name == 'battlenet-oauth2' and is_new:
++            data = backend.strategy.request_data()
++            if data.get('character_name') is None:
++                # New user and didn't pick a character name yet, so we render
++                # and send a form to pick one. The form must do a POST/GET
++                # request to the same URL (/complete/battlenet-oauth2/). In this
++                # example we expect the user option under the key:
++                #   character_name
++                # you have to filter the result list according to your needs.
++                # In this example, only guild members are allowed to sign up.
++                char_list = [
++                    c['name'] for c in backend.get_characters(response.get('access_token'))
++                        if 'guild' in c and c['guild'] == '<guild name>'
++                ]
++                return render_to_response('pick_character_form.html', {'charlist': char_list, })
++            else:
++                # The user selected a character name
++                return {'username': data.get('character_name')}
++
++Don't forget to add the partial to the pipeline::
++
++    SOCIAL_AUTH_PIPELINE = (
++        'social.pipeline.social_auth.social_details',
++        'social.pipeline.social_auth.social_uid',
++        'social.pipeline.social_auth.auth_allowed',
++        'social.pipeline.social_auth.social_user',
++        'social.pipeline.user.get_username',
++        'path.to.pick_character_name',
++        'social.pipeline.user.create_user',
++        'social.pipeline.social_auth.associate_user',
++        'social.pipeline.social_auth.load_extra_data',
++        'social.pipeline.user.user_details',
++    )
++
++It needs to be somewhere before create_user because the partial will change the
++username according to the users choice.
++
++
++Re-prompt Google OAuth2 users to refresh the ``refresh_token``
++--------------------------------------------------------------
++
++A ``refresh_token`` also expire, a ``refresh_token`` can be lost, but they can
++also be refreshed (or re-fetched) if you ask to Google the right way. In order
++to do so, set this setting::
++
++    SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {
++        'access_type': 'offline',
++        'approval_prompt': 'auto'
++    }
++
++Then link the users to ``/login/google-oauth2?approval_prompt=force``. If you
++want to refresh the ``refresh_token`` only on those users that don't  have it,
++do it with a pipeline function::
++
++    def redirect_if_no_refresh_token(backend, response, social, *args, **kwargs):
++        if backend.name == 'google-oauth2' and social and \
++           response.get('refresh_token') is None and \
++           social.extra_data.get('refresh_token') is None:
++            return redirect('/login/google-oauth2?approval_prompt=force')
++
++Set this pipeline after ``social_user``::
++
++    SOCIAL_AUTH_PIPELINE = (
++        'social.pipeline.social_auth.social_details',
++        'social.pipeline.social_auth.social_uid',
++        'social.pipeline.social_auth.auth_allowed',
++        'social.pipeline.social_auth.social_user',
++        'path.to.redirect_if_no_refresh_token',
++        'social.pipeline.user.get_username',
++        'social.pipeline.user.create_user',
++        'social.pipeline.social_auth.associate_user',
++        'social.pipeline.social_auth.load_extra_data',
++        'social.pipeline.user.user_details',
++    )
++
++
++.. _python-social-auth: https://github.com/omab/python-social-auth
++.. _People API endpoint: https://developers.google.com/+/api/latest/people/list
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..cc8bcad
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+add-docs.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-social-auth.git



More information about the Python-modules-commits mailing list