From 68d9bcdf37349e18bc4ab8e34168cd9277116f58 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mat=C3=ADas=20Aguirre?= Date: Wed, 14 Mar 2012 21:04:13 -0300 Subject: [PATCH] Add tokens property to easilly access tokens per backend. Closes #290 --- README.rst | 25 +++++++++++++++++++++++++ doc/index.rst | 1 + doc/tokens.rst | 23 +++++++++++++++++++++++ social_auth/backends/__init__.py | 15 +++++++++++++++ social_auth/backends/twitter.py | 14 ++++++++++++++ social_auth/models.py | 11 +++++++++++ 6 files changed, 89 insertions(+) create mode 100644 doc/tokens.rst diff --git a/README.rst b/README.rst index 23eb502..3865756 100644 --- a/README.rst +++ b/README.rst @@ -563,6 +563,30 @@ created:: socialauth_registered.connect(new_users_handler, sender=None) + +Tokens +------ + +Almost every service covered provide some kind of API that is protected with +``access_token`` or token pairs (like `Twitter OAuth keys`_). These tokens are +gathered by the authentication mechanism and stored in +``UserSocialAuth.extra_data``. + +``UserSocialAuth`` has a property named ``tokens`` to easilly access this +useful values, it will return a dictionary containing the tokens values. +A simple usage example:: + + >>> from pprint import pprint + >>> from social_auth.models import UserSocialAuth + >>> instance = UserSocialAuth.objects.filter(provider='twitter').get(...) + >>> pprint(instance.tokens) + {u'oauth_token': u'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + u'oauth_token_secret': u'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} + >>> instance = UserSocialAuth.objects.filter(provider='facebook').get(...) + >>> pprint(instance.tokens) + {u'access_token': u'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'} + + Backends -------- @@ -1070,3 +1094,4 @@ Base work is copyrighted by: .. _BrowserID: https://browserid.org .. _Instagram API: http://instagr.am/developer/ .. _django-social-auth discussion list: https://groups.google.com/group/django-social-auth +.. _Twitter OAuth keys: https://dev.twitter.com/docs/auth/authorizing-request diff --git a/doc/index.rst b/doc/index.rst index d9b711e..9f706a1 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -19,6 +19,7 @@ Contents: deprecated signals + tokens contributions testing use_cases diff --git a/doc/tokens.rst b/doc/tokens.rst new file mode 100644 index 0000000..b486f39 --- /dev/null +++ b/doc/tokens.rst @@ -0,0 +1,23 @@ +Tokens +------ + +Almost every service covered provide some kind of API that is protected with +``access_token`` or token pairs (like `Twitter OAuth keys`_). These tokens are +gathered by the authentication mechanism and stored in +``UserSocialAuth.extra_data``. + +``UserSocialAuth`` has a property named ``tokens`` to easilly access this +useful values, it will return a dictionary containing the tokens values. +A simple usage example:: + + >>> from pprint import pprint + >>> from social_auth.models import UserSocialAuth + >>> instance = UserSocialAuth.objects.filter(provider='twitter').get(...) + >>> pprint(instance.tokens) + {u'oauth_token': u'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + u'oauth_token_secret': u'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} + >>> instance = UserSocialAuth.objects.filter(provider='facebook').get(...) + >>> pprint(instance.tokens) + {u'access_token': u'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'} + +.. _Twitter OAuth keys: https://dev.twitter.com/docs/auth/authorizing-request diff --git a/social_auth/backends/__init__.py b/social_auth/backends/__init__.py index 766bb6f..c38e60a 100644 --- a/social_auth/backends/__init__.py +++ b/social_auth/backends/__init__.py @@ -169,6 +169,21 @@ class SocialAuthBackend(ModelBackend): """ raise NotImplementedError('Implement in subclass') + @classmethod + def tokens(cls, instance): + """Return the tokens needed to authenticate the access to any API the + service might provide. The return value will be a dictionary with the + token type name as key and the token value. + + instance must be a UserSocialAuth instance. + """ + if instance.extra_data and 'access_token' in instance.extra_data: + return { + 'access_token': instance.extra_data['access_token'] + } + else: + return {} + def get_user(self, user_id): """ Return user with given ID from the User model used by this backend diff --git a/social_auth/backends/twitter.py b/social_auth/backends/twitter.py index bee56ed..cfdd021 100644 --- a/social_auth/backends/twitter.py +++ b/social_auth/backends/twitter.py @@ -45,6 +45,20 @@ class TwitterBackend(OAuthBackend): 'first_name': first_name, 'last_name': last_name} + @classmethod + def tokens(cls, instance): + """Return the tokens needed to authenticate the access to any API the + service might provide. Twitter uses a pair of OAuthToken consisting on + a oauth_token and oauth_token_secret. + + instance must be a UserSocialAuth instance. + """ + token = super(TwitterBackend, cls).tokens(instance) + if token and 'access_token' in token: + token = dict(tok.split('=') + for tok in token['access_token'].split('&')) + return token + class TwitterAuth(ConsumerBasedOAuth): """Twitter OAuth authentication mechanism""" diff --git a/social_auth/models.py b/social_auth/models.py index b700329..91db50d 100644 --- a/social_auth/models.py +++ b/social_auth/models.py @@ -37,6 +37,17 @@ class UserSocialAuth(models.Model): """Return associated user unicode representation""" return unicode(self.user) + @property + def tokens(self): + """Return access_token stored in extra_data or None""" + # Make import here to avoid recursive imports :-/ + from social_auth.backends import get_backends + backend = get_backends().get(self.provider) + if backend: + return backend.AUTH_BACKEND.tokens(self) + else: + return {} + def expiration_delta(self): """Return saved session expiration seconds if any. Is retuned in the form of a timedelta data type. None is returned if there's no -- 2.39.5