From 000af554fcf35bcc430969e64b69f16240b5f666 Mon Sep 17 00:00:00 2001 From: iampark Date: Sun, 18 Sep 2016 23:57:45 -0700 Subject: [PATCH 1/6] Create lyft.py --- social/backends/lyft.py | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 social/backends/lyft.py diff --git a/social/backends/lyft.py b/social/backends/lyft.py new file mode 100644 index 000000000..5aaea80ee --- /dev/null +++ b/social/backends/lyft.py @@ -0,0 +1,58 @@ +""" +Lyft OAuth2 backend, docs at: + https://developer.lyft.com/docs +""" +from social.backends.oauth import BaseOAuth2 + +class LyftOAuth2(BaseOAuth2): + + name = 'lyft' + ID_KEY = 'id' + + SCOPE_SEPARATOR = ' ' + AUTHORIZATION_URL = 'https://api.lyft.com/oauth/authorize' + ACCESS_TOKEN_URL = 'https://api.lyft.com/oauth/token' + ACCESS_TOKEN_METHOD = 'POST' + REFRESH_TOKEN_URL = 'https://api.lyft.com/oauth/revoke_refresh_token' + + DEFAULT_SCOPE = ['public', 'profile', 'rides.read', 'rides.request'] + + RESPONSE_TYPE = 'code' + STATE_PARAMETER = 'asdf' + + EXTRA_DATA = [ + # ('id', 'id'), + ('refresh_token', 'refresh_token'), + ('token_type', 'token_type'), + ('expires_in', 'expires_in'), + ('scope', 'scope'), + ] + + def get_user_details(self, response): + """Return user details from Lyft account""" + + print "get_user_details", response + + # fullname, first_name, last_name = self.get_user_names(response['name']) + return {'id': response['id']} + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + response = kwargs.pop('response') + return self.get_json('https://api.lyft.com/v1/profile', headers={ + 'Authorization': '{0} {1}'.format( + response.get('token_type'), access_token + ) + } + ) + + def auth_complete_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return { + 'grant_type': 'authorization_code', + 'code': self.data['code'] + } + + def auth_complete_credentials(self): + return self.get_key_and_secret() + From 6c00710c8367e7e460db90e2b0309c95ea6dc915 Mon Sep 17 00:00:00 2001 From: iampark Date: Sun, 18 Sep 2016 23:58:14 -0700 Subject: [PATCH 2/6] Create test_lyft.py --- social/tests/backends/test_lyft.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 social/tests/backends/test_lyft.py diff --git a/social/tests/backends/test_lyft.py b/social/tests/backends/test_lyft.py new file mode 100644 index 000000000..a163a11b7 --- /dev/null +++ b/social/tests/backends/test_lyft.py @@ -0,0 +1,21 @@ +import json + +from social.tests.backends.oauth import OAuth2Test + + +class LyftOAuth2Test(OAuth2Test): + backend_path = 'social.backends.lyft.LyftOAuth2' + access_token_body = json.dumps({ + 'access_token': 'foobar', + 'refresh_token': 'barfoo', + 'token_type': 'bearer', + 'expires_in': 3600, + 'scope': 'one two three' + }) + # expected_username = 'acct_foobar' + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() From 0ee17034122fa695fe5463866a598734ae66bb13 Mon Sep 17 00:00:00 2001 From: iampark Date: Sat, 8 Oct 2016 00:45:33 -0700 Subject: [PATCH 3/6] Update README.rst --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index f2b051689..7640c140d 100644 --- a/README.rst +++ b/README.rst @@ -85,6 +85,7 @@ or current ones extended): * Linkedin_ OAuth1 * Live_ OAuth2 * Livejournal_ OpenId + * Lyft_ OAuth2 * LoginRadius_ OAuth2 and Application Auth * Mailru_ OAuth2 * MapMyFitness_ OAuth2 @@ -267,6 +268,7 @@ check `django-social-auth LICENSE`_ for details: .. _Linkedin: https://www.linkedin.com .. _Live: https://live.com .. _Livejournal: http://livejournal.com +.. _Lyft: http://lyft.com .. _Khan Academy: https://github.com/Khan/khan-api/wiki/Khan-Academy-API-Authentication .. _Mailru: https://mail.ru .. _MapMyFitness: http://www.mapmyfitness.com/ From 9a3c98dd962c4ee706d9c9b820c8f9652045dec6 Mon Sep 17 00:00:00 2001 From: iampark Date: Sat, 8 Oct 2016 00:50:12 -0700 Subject: [PATCH 4/6] Create lyft.rst --- docs/backends/lyft.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/backends/lyft.rst diff --git a/docs/backends/lyft.rst b/docs/backends/lyft.rst new file mode 100644 index 000000000..ff2e11d4b --- /dev/null +++ b/docs/backends/lyft.rst @@ -0,0 +1,28 @@ +Lyft +========= + +Lyft implements OAuth2 as its authorization service. To setup a Lyft backend: + +1. Register a new application via the `Lyft Developer Portal`_. + +2. Add the Lyft OAuth2 backend as an option in your settings:: + + SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( + ... + 'social.backends.lyft.LyftOAuth2', + ... + ) + +3. Use the ``Client Id`` and ``Client Secret`` from the Developer Portal into your settings:: + + SOCIAL_AUTH_LYFT_KEY = '' + SOCIAL_AUTH_LYFT_SECRET = '' + +4. Specify the scope that your app should have access to:: + + SOCIAL_AUTH_LYFT_SCOPE = ['public', 'profile', 'rides.read', 'rides.request'] + +To learn more about the API and the calls that are available, read the `Lyft API Documentation`_. + +.. _Lyft Developer Portal: https://developer.lyft.com/ +.. _Lyft API Documentation: https://developer.lyft.com/docs From 382b23125b3715eede7643e3667ab6da95a56b94 Mon Sep 17 00:00:00 2001 From: iampark Date: Sat, 8 Oct 2016 00:51:25 -0700 Subject: [PATCH 5/6] Update lyft.py --- social/backends/lyft.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/social/backends/lyft.py b/social/backends/lyft.py index 5aaea80ee..9a6a565ff 100644 --- a/social/backends/lyft.py +++ b/social/backends/lyft.py @@ -1,6 +1,6 @@ """ -Lyft OAuth2 backend, docs at: - https://developer.lyft.com/docs +Lyft OAuth2 backend. Read more about the + API at https://developer.lyft.com/docs """ from social.backends.oauth import BaseOAuth2 @@ -13,7 +13,8 @@ class LyftOAuth2(BaseOAuth2): AUTHORIZATION_URL = 'https://api.lyft.com/oauth/authorize' ACCESS_TOKEN_URL = 'https://api.lyft.com/oauth/token' ACCESS_TOKEN_METHOD = 'POST' - REFRESH_TOKEN_URL = 'https://api.lyft.com/oauth/revoke_refresh_token' + REFRESH_TOKEN_URL = 'https://api.lyft.com/oauth/token' + USER_DATA_URL = 'https://api.lyft.com/v1/profile' DEFAULT_SCOPE = ['public', 'profile', 'rides.read', 'rides.request'] @@ -21,7 +22,9 @@ class LyftOAuth2(BaseOAuth2): STATE_PARAMETER = 'asdf' EXTRA_DATA = [ - # ('id', 'id'), + ('id', 'id'), + ('username', 'username'), + ('access_token', 'access_token'), ('refresh_token', 'refresh_token'), ('token_type', 'token_type'), ('expires_in', 'expires_in'), @@ -31,17 +34,18 @@ class LyftOAuth2(BaseOAuth2): def get_user_details(self, response): """Return user details from Lyft account""" - print "get_user_details", response - - # fullname, first_name, last_name = self.get_user_names(response['name']) - return {'id': response['id']} + return { + 'id': response['id'], + 'username': response['id'] + } def user_data(self, access_token, *args, **kwargs): """Loads user data from service""" response = kwargs.pop('response') - return self.get_json('https://api.lyft.com/v1/profile', headers={ - 'Authorization': '{0} {1}'.format( - response.get('token_type'), access_token + + return self.get_json(self.USER_DATA_URL, headers={ + 'Authorization': 'Bearer {0}'.format( + access_token ) } ) @@ -56,3 +60,8 @@ def auth_complete_params(self, state=None): def auth_complete_credentials(self): return self.get_key_and_secret() + def refresh_token_params(self, refresh_token, *args, **kwargs): + return {'refresh_token': refresh_token, + 'grant_type': 'refresh_token'} + + From 8372117b0cce63744558b0d1e78f439aeab895f4 Mon Sep 17 00:00:00 2001 From: iampark Date: Sat, 8 Oct 2016 00:52:01 -0700 Subject: [PATCH 6/6] Update test_lyft.py --- social/tests/backends/test_lyft.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/social/tests/backends/test_lyft.py b/social/tests/backends/test_lyft.py index a163a11b7..646e0deb1 100644 --- a/social/tests/backends/test_lyft.py +++ b/social/tests/backends/test_lyft.py @@ -4,15 +4,25 @@ class LyftOAuth2Test(OAuth2Test): + backend_path = 'social.backends.lyft.LyftOAuth2' + + user_data_url = \ + 'https://api.lyft.com/v1/profile' + access_token_body = json.dumps({ - 'access_token': 'foobar', - 'refresh_token': 'barfoo', + 'access_token': 'atoken_foo', + 'refresh_token': 'rtoken_bar', 'token_type': 'bearer', 'expires_in': 3600, - 'scope': 'one two three' + 'scope': 'public profile rides.read rides.request', + 'id': 'user_foobar' + }) + + user_data_body = json.dumps({ + 'id': 'user_foobar' }) - # expected_username = 'acct_foobar' + expected_username = 'user_foobar' def test_login(self): self.do_login()