class PayPal(OAuth2): """ PayPal |oauth2| provider. * Dashboard: https://developer.paypal.com/webapps/developer/applications * Docs: https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/ * API reference: https://developer.paypal.com/webapps/developer/docs/api/ .. note:: Paypal doesn't redirect the **user** to authorize your app! It grants you an **access token** based on your **app's** key and secret instead. """ _x_use_authorization_header = True supported_user_attributes = core.SupportedUserAttributes() @classmethod def _x_request_elements_filter(cls, request_type, request_elements, credentials): if request_type == cls.ACCESS_TOKEN_REQUEST_TYPE: url, method, params, headers, body = request_elements params['grant_type'] = 'client_credentials' request_elements = core.RequestElements(url, method, params, headers, body) return request_elements user_authorization_url = '' access_token_url = 'https://api.sandbox.paypal.com/v1/oauth2/token' user_info_url = ''
class Bitbucket(OAuth1): """ Bitbucket |oauth1| provider. * Dashboard: https://bitbucket.org/account/user/peterhudec/api * Docs: https://confluence.atlassian.com/display/BITBUCKET/oauth+Endpoint * API reference: https://confluence.atlassian.com/display/BITBUCKET/Using+the+Bitbucket+REST+APIs Supported :class:`.User` properties: * first_name * id * last_name * link * name * picture * username Unsupported :class:`.User` properties: * birth_date * city * country * email * gender * locale * location * nickname * phone * postal_code * timezone """ supported_user_attributes = core.SupportedUserAttributes( first_name=True, id=True, last_name=True, link=True, name=True, picture=True, username=True ) request_token_url = 'https://bitbucket.org/!api/1.0/oauth/request_token' user_authorization_url = 'https://bitbucket.org/!api/1.0/oauth/authenticate' access_token_url = 'https://bitbucket.org/!api/1.0/oauth/access_token' user_info_url = 'https://api.bitbucket.org/1.0/user' @staticmethod def _x_user_parser(user, data): _user = data.get('user', {}) user.username = user.id = _user.get('username') user.name = _user.get('display_name') user.first_name = _user.get('first_name') user.last_name = _user.get('last_name') user.picture = _user.get('avatar') user.link = 'https://bitbucket.org/api{0}'\ .format(_user.get('resource_uri')) return user
class Twitter(OAuth1): """ Twitter |oauth1| provider. * Dashboard: https://dev.twitter.com/apps * Docs: https://dev.twitter.com/docs * API reference: https://dev.twitter.com/docs/api Supported :class:`.User` properties: * id * link * locale * location * name * picture * username Unsupported :class:`.User` properties: * birth_date * city * country * email * gender * first_name * last_name * nickname * phone * postal_code * timezone """ supported_user_attributes = core.SupportedUserAttributes( id=True, link=True, locale=True, location=True, name=True, picture=True, username=True ) request_token_url = 'https://api.twitter.com/oauth/request_token' user_authorization_url = 'https://api.twitter.com/oauth/authenticate' access_token_url = 'https://api.twitter.com/oauth/access_token' user_info_url = 'https://api.twitter.com/1.1/account/verify_credentials.json' supports_jsonp = True @staticmethod def _x_user_parser(user, data): user.username = data.get('screen_name') user.id = data.get('id') or data.get('user_id') user.picture = data.get('profile_image_url') user.locale = data.get('lang') user.link = data.get('url') return user
class Relayr(OAuth2): """ Relayr |oauth2| provider. .. warning:: |no-csrf| * Dashboard: https://developer.relayr.io * Docs: https://developer.relayr.io/documents/Welcome/Introduction * Public API reference: https://developer.relayr.io/documents/relayrAPI/Introduction Supported :class:`.User` properties: * name * id * email """ # https://developer.relayr.io/documents/Welcome/OAuthReference supported_user_attributes = core.SupportedUserAttributes(name=True, id=True, email=True) supports_csrf_protection = False _x_use_authorization_header = False user_authorization_url = 'https://api.relayr.io/oauth2/auth' access_token_url = 'https://api.relayr.io/oauth2/token' user_info_url = 'https://api.relayr.io/oauth2/user-info' user_info_scope = ['access-own-user-info'] def __init__(self, *args, **kwargs): super(Relayr, self).__init__(*args, **kwargs) if self.offline: if not 'grant_type' in self.access_token_params: self.access_token_params['grant_type'] = 'refresh_token' def _x_scope_parser(self, scope): # relayr has space-separated scopes return ' '.join(scope) @staticmethod def _x_user_parser(user, data): client = Client(token=user.credentials.token) usr = client.get_user() user.name = usr.name user.id = usr.id user.email = usr.email user.transmitters = list(usr.get_transmitters()) user.transmitters_devices = {} for t in user.transmitters: user.transmitters_devices[ t.name] = client.api.get_transmitter_devices(t.id) return user
class Flickr(OAuth1): """ Flickr |oauth1| provider. * Dashboard: https://www.flickr.com/services/apps/ * Docs: https://www.flickr.com/services/api/auth.oauth.html * API reference: https://www.flickr.com/services/api/ Supported :class:`.User` properties: * id * name * username Unsupported :class:`.User` properties: * birth_date * city * country * email * first_name * gender * last_name * link * locale * location * nickname * phone * picture * postal_code * timezone """ supported_user_attributes = core.SupportedUserAttributes( id=True, name=True, username=True ) request_token_url = 'http://www.flickr.com/services/oauth/request_token' user_authorization_url = 'http://www.flickr.com/services/oauth/authorize' access_token_url = 'http://www.flickr.com/services/oauth/access_token' user_info_url = None supports_jsonp = True @staticmethod def _x_user_parser(user, data): _user = data.get('user', {}) user.name = data.get('fullname') or _user.get('username', {}).get('_content') user.id = data.get('user_nsid') or _user.get('id') return user
class DeviantART(OAuth2): """ DeviantART |oauth2| provider. * Dashboard: https://www.deviantart.com/settings/myapps * Docs: https://www.deviantart.com/developers/authentication * API reference: http://www.deviantart.com/developers/oauth2 Supported :class:`.User` properties: * name * picture * username Unsupported :class:`.User` properties: * birth_date * city * country * email * first_name * gender * id * last_name * link * locale * nickname * phone * postal_code * timezone """ user_authorization_url = 'https://www.deviantart.com/oauth2/draft15/authorize' access_token_url = 'https://www.deviantart.com/oauth2/draft15/token' user_info_url = 'https://www.deviantart.com/api/oauth2/user/whoami' user_info_scope = ['basic'] supported_user_attributes = core.SupportedUserAttributes(name=True, picture=True, username=True) def __init__(self, *args, **kwargs): super(DeviantART, self).__init__(*args, **kwargs) if self.offline: if not 'grant_type' in self.access_token_params: self.access_token_params['grant_type'] = 'refresh_token' @staticmethod def _x_user_parser(user, data): user.picture = data.get('usericonurl') return user
class Tumblr(OAuth1): """ Tumblr |oauth1| provider. * Dashboard: http://www.tumblr.com/oauth/apps * Docs: http://www.tumblr.com/docs/en/api/v2#auth * API reference: http://www.tumblr.com/docs/en/api/v2 Supported :class:`.User` properties: * id * name * username Unsupported :class:`.User` properties: * birth_date * city * country * email * gender * first_name * last_name * link * locale * location * nickname * phone * picture * postal_code * timezone """ supported_user_attributes = core.SupportedUserAttributes( id=True, name=True, username=True ) request_token_url = 'http://www.tumblr.com/oauth/request_token' user_authorization_url = 'http://www.tumblr.com/oauth/authorize' access_token_url = 'http://www.tumblr.com/oauth/access_token' user_info_url = 'http://api.tumblr.com/v2/user/info' supports_jsonp = True @staticmethod def _x_user_parser(user, data): _user = data.get('response', {}).get('user', {}) user.username = user.id = _user.get('name') return user
class SAEON(OAuth2): """ SAEON |oauth2| provider. * Dashboard: https://github.com/settings/developers * Docs: http://developer.github.com/v3/#authentication * API reference: http://developer.github.com/v3/ .. note:: GitHub API `documentation <http://developer.github.com/v3/#user-agent-required>`_ sais: all API requests MUST include a valid ``User-Agent`` header. You can apply a default ``User-Agent`` header for all API calls in the config like this: .. code-block:: python :emphasize-lines: 6 CONFIG = { 'github': { 'class_': oauth2.GitHub, 'consumer_key': '#####', 'consumer_secret': '#####', 'access_headers': {'User-Agent': 'Awesome-Octocat-App'}, } } Supported :class:`.User` properties: * email * id * link * location * name * picture * username Unsupported :class:`.User` properties: * birth_date * city * country * first_name * gender * last_name * locale * nickname * phone * postal_code * timezone """ user_authorization_url = "https://identity.saeon.nimbusservices.co.za/oauth2/connect/authorize" access_token_url = "https://identity.saeon.nimbusservices.co.za/oauth2/connect/token" user_info_url = "https://identity.saeon.nimbusservices.co.za/oauth2/connect/userinfo" same_origin = False supported_user_attributes = core.SupportedUserAttributes( email=True, id=True, username=True, name=True, link=True, location=False, picture=False, ) @staticmethod def _x_user_parser(user, data): logging.debug('_x_user_parser: data = %s' % data) user.username = data.get('preferred_username') user.email = data.get('email') user.id = data.get('email') user.fullname = "%s %s" % (data.get('given_name'), data.get('family_name')) user.name = user.fullname user.link = 'http://www.saeon.ac.za' #data.get('html_url') #user.picture = data.get('avatar_url') logging.debug('_x_user_parser: user = %s' % user) return user @classmethod def _x_credentials_parser(cls, credentials, data): if data.get('token_type') == 'Bearer': credentials.token_type = cls.BEARER return credentials
class GitHub(OAuth2): """ GitHub |oauth2| provider. * Dashboard: https://github.com/settings/applications/ * Docs: http://developer.github.com/v3/#authentication * API reference: http://developer.github.com/v3/ .. note:: GitHub API `documentation <http://developer.github.com/v3/#user-agent-required>`_ sais: all API requests MUST include a valid ``User-Agent`` header. You can apply a default ``User-Agent`` header for all API calls in the config like this: .. code-block:: python :emphasize-lines: 6 CONFIG = { 'github': { 'class_': oauth2.GitHub, 'consumer_key': '#####', 'consumer_secret': '#####', 'access_headers': {'User-Agent': 'Awesome-Octocat-App'}, } } * city * country * email * id * link * name * picture * username Unsupported :class:`.User` properties: * birth_date * first_name * gender * last_name * locale * nickname * phone * postal_code * timezone """ user_authorization_url = 'https://github.com/login/oauth/authorize' access_token_url = 'https://github.com/login/oauth/access_token' user_info_url = 'https://api.github.com/user' same_origin = False supported_user_attributes = core.SupportedUserAttributes(city=True, country=True, email=True, id=True, link=True, name=True, picture=True, username=True) @staticmethod def _x_user_parser(user, data): user.username = data.get('login') user.picture = data.get('avatar_url') user.link = data.get('html_url') location = data.get('location', '') if location: split_location = location.split(',') user.city = split_location[0].strip() if len(split_location) > 1: user.country = split_location[1].strip() return user @classmethod def _x_credentials_parser(cls, credentials, data): if data.get('token_type') == 'bearer': credentials.token_type = cls.BEARER return credentials
class Meetup(OAuth1): """ Meetup |oauth1| provider. .. note:: Meetup also supports |oauth2| but you need the **user ID** to update the **user** info, which they don't provide in the |oauth2| access token response. * Dashboard: http://www.meetup.com/meetup_api/oauth_consumers/ * Docs: http://www.meetup.com/meetup_api/auth/#oauth * API: http://www.meetup.com/meetup_api/docs/ Supported :class:`.User` properties: * city * country * id * link * locale * location * name * picture Unsupported :class:`.User` properties: * birth_date * email * first_name * gender * last_name * nickname * phone * postal_code * timezone * username """ supported_user_attributes = core.SupportedUserAttributes( city=True, country=True, id=True, link=True, locale=True, location=True, name=True, picture=True ) request_token_url = 'https://api.meetup.com/oauth/request/' user_authorization_url = 'http://www.meetup.com/authorize/' access_token_url = 'https://api.meetup.com/oauth/access/' user_info_url = 'https://api.meetup.com/2/member/{id}' @staticmethod def _x_user_parser(user, data): user.id = data.get('id') or data.get('member_id') user.locale = data.get('lang') user.picture = data.get('photo', {}).get('photo_link') return user
class Plurk(OAuth1): """ Plurk |oauth1| provider. * Dashboard: http://www.plurk.com/PlurkApp/ * Docs: * API: http://www.plurk.com/API * API explorer: http://www.plurk.com/OAuth/test/ Supported :class:`.User` properties: * birth_date * city * country * email * gender * id * link * locale * location * name * nickname * picture * timezone * username Unsupported :class:`.User` properties: * first_name * last_name * phone * postal_code """ supported_user_attributes = core.SupportedUserAttributes( birth_date=True, city=True, country=True, email=True, gender=True, id=True, link=True, locale=True, location=True, name=True, nickname=True, picture=True, timezone=True, username=True ) request_token_url = 'http://www.plurk.com/OAuth/request_token' user_authorization_url = 'http://www.plurk.com/OAuth/authorize' access_token_url = 'http://www.plurk.com/OAuth/access_token' user_info_url = 'http://www.plurk.com/APP/Profile/getOwnProfile' @staticmethod def _x_user_parser(user, data): _user = data.get('user_info', {}) user.email = _user.get('email') user.gender = _user.get('gender') user.id = _user.get('id') or _user.get('uid') user.locale = _user.get('default_lang') user.name = _user.get('full_name') user.nickname = _user.get('nick_name') user.picture = 'http://avatars.plurk.com/{0}-big2.jpg'.format(user.id) user.timezone = _user.get('timezone') user.username = _user.get('display_name') user.link = 'http://www.plurk.com/{0}/'.format(user.username) user.city, user.country = _user.get('location', ',').split(',') user.city = user.city.strip() user.country = user.country.strip() _bd = _user.get('date_of_birth') if _bd: try: user.birth_date = datetime.datetime.strptime( _bd, "%a, %d %b %Y %H:%M:%S %Z" ) except ValueError: pass return user
class Xing(OAuth1): """ Xing |oauth1| provider. * Dashboard: https://dev.xing.com/applications * Docs: https://dev.xing.com/docs/authentication * API reference: https://dev.xing.com/docs/resources Supported :class:`.User` properties: * birth_date * city * country * email * first_name * gender * id * last_name * link * locale * location * name * phone * picture * postal_code * timezone * username Unsupported :class:`.User` properties: * nickname """ request_token_url = 'https://api.xing.com/v1/request_token' user_authorization_url = 'https://api.xing.com/v1/authorize' access_token_url = 'https://api.xing.com/v1/access_token' user_info_url = 'https://api.xing.com/v1/users/me' supported_user_attributes = core.SupportedUserAttributes( birth_date=True, city=True, country=True, email=True, first_name=True, gender=True, id=True, last_name=True, link=True, locale=True, location=True, name=True, phone=True, picture=True, postal_code=True, timezone=True, username=True, ) @staticmethod def _x_user_parser(user, data): _users = data.get('users', []) if _users and _users[0]: _user = _users[0] user.id = _user.get('id') user.name = _user.get('display_name') user.first_name = _user.get('first_name') user.last_name = _user.get('last_name') user.gender = _user.get('gender') user.timezone = _user.get('time_zone', {}).get('name') user.email = _user.get('active_email') user.link = _user.get('permalink') user.username = _user.get('page_name') user.picture = _user.get('photo_urls', {}).get('large') _address = _user.get('business_address', {}) if _address: user.city = _address.get('city') user.country = _address.get('country') user.postal_code = _address.get('zip_code') user.phone = (_address.get('phone', '') or _address.get('mobile_phone', '')).replace('|', '') _languages = list(_user.get('languages', {}).keys()) if _languages and _languages[0]: user.locale = _languages[0] _birth_date = _user.get('birth_date', {}) _year = _birth_date.get('year') _month = _birth_date.get('month') _day = _birth_date.get('day') if _year and _month and _day: user.birth_date = datetime.datetime(_year, _month, _day) return user
class Flickr(OAuth1): """ Flickr |oauth1| provider. * Dashboard: https://www.flickr.com/services/apps/ * Docs: https://www.flickr.com/services/api/auth.oauth.html * API reference: https://www.flickr.com/services/api/ Supported :class:`.User` properties: * id * name * username Unsupported :class:`.User` properties: * birth_date * city * country * email * first_name * gender * last_name * link * locale * location * nickname * phone * picture * postal_code * timezone .. note:: If you encounter the "Oops! Flickr doesn't recognise the permission set." message, you need to add the ``perms=read`` or ``perms=write`` parameter to the *user authorization request*. You can do it by adding the ``user_authorization_params`` key to the :doc:`config`: .. code-block:: python :emphasize-lines: 6 CONFIG = { 'flickr': { 'class_': oauth1.Flickr, 'consumer_key': '##########', 'consumer_secret': '##########', 'user_authorization_params': dict(perms='read'), }, } """ supported_user_attributes = core.SupportedUserAttributes( id=True, name=True, username=True ) request_token_url = 'http://www.flickr.com/services/oauth/request_token' user_authorization_url = 'http://www.flickr.com/services/oauth/authorize' access_token_url = 'http://www.flickr.com/services/oauth/access_token' user_info_url = None supports_jsonp = True @staticmethod def _x_user_parser(user, data): _user = data.get('user', {}) user.name = data.get('fullname') or _user.get('username', {}).get('_content') user.id = data.get('user_nsid') or _user.get('id') return user
class Twitter(OAuth1): """ Twitter |oauth1| provider. * Dashboard: https://dev.twitter.com/apps * Docs: https://dev.twitter.com/docs * API reference: https://dev.twitter.com/docs/api .. note:: To prevent multiple authorization attempts, you should enable the option: ``Allow this application to be used to Sign in with Twitter`` in the Twitter 'Application Management' page. (http://apps.twitter.com) Supported :class:`.User` properties: * email * city * country * id * link * locale * location * name * picture * username Unsupported :class:`.User` properties: * birth_date * email * gender * first_name * last_name * locale * nickname * phone * postal_code * timezone """ supported_user_attributes = core.SupportedUserAttributes(city=True, country=True, id=True, email=False, link=True, locale=False, location=True, name=True, picture=True, username=True) request_token_url = 'https://api.twitter.com/oauth/request_token' user_authorization_url = 'https://api.twitter.com/oauth/authenticate' access_token_url = 'https://api.twitter.com/oauth/access_token' user_info_url = ( 'https://api.twitter.com/1.1/account/verify_credentials.json?' 'include_entities=true&include_email=true') supports_jsonp = True @staticmethod def _x_user_parser(user, data): user.username = data.get('screen_name') user.id = data.get('id') or data.get('user_id') user.picture = data.get('profile_image_url') user.locale = data.get('lang') user.link = data.get('url') _location = data.get('location', '') if _location: user.location = _location.strip() _split_location = _location.split(',') if len(_split_location) > 1: _city, _country = _split_location user.country = _country.strip() else: _city = _split_location[0] user.city = _city.strip() return user
class Yahoo(OAuth1): """ Yahoo |oauth1| provider. * Dashboard: https://developer.apps.yahoo.com/dashboard/ * Docs: http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html * API: http://developer.yahoo.com/everything.html * API explorer: http://developer.yahoo.com/yql/console/ Supported :class:`.User` properties: * birth_date * city * country * gender * id * link * location * name * nickname * picture Unsupported :class:`.User` properties: * locale * phone * postal_code * timezone * username """ supported_user_attributes = core.SupportedUserAttributes( birth_date=True, city=True, country=True, gender=True, id=True, link=True, location=True, name=True, nickname=True, picture=True ) request_token_url = 'https://api.login.yahoo.com/oauth/v2/get_request_token' user_authorization_url = 'https://api.login.yahoo.com/oauth/v2/request_auth' access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token' user_info_url = ('https://query.yahooapis.com/v1/yql?q=select%20*%20from%20' 'social.profile%20where%20guid%3Dme%3B&format=json') same_origin = False supports_jsonp = True @staticmethod def _x_user_parser(user, data): _user = data.get('query', {}).get('results', {}).get('profile', {}) user.id = _user.get('guid') user.gender = _user.get('gender') user.nickname = _user.get('nickname') user.link = _user.get('profileUrl') emails = _user.get('emails') if isinstance(emails, list): for email in emails: if 'primary' in list(email.keys()): user.email = email.get('handle') elif isinstance(emails, dict): user.email = emails.get('handle') user.picture = _user.get('image', {}).get('imageUrl') user.city, user.country = _user.get('location', ',').split(',') user.city = user.city.strip() user.country = user.country.strip() _date = _user.get('birthdate') _year = _user.get('birthYear') if _date and _year: _full = _date + '/' + _year try: user.birth_date = datetime.datetime.strptime(_full, "%m/%d/%Y") except: user.birth_date = _full return user
class Reddit(OAuth2): """ Reddit |oauth2| provider. .. note:: Currently credentials refreshment returns ``{"error": "invalid_request"}``. * Dashboard: https://ssl.reddit.com/prefs/apps * Docs: https://github.com/reddit/reddit/wiki/OAuth2 * API reference: http://www.reddit.com/dev/api Supported :class:`.User` properties: * id * username Unsupported :class:`.User` properties: * birth_date * country * city * email * first_name * gender * last_name * link * locale * name * nickname * phone * picture * postal_code * timezone """ user_authorization_url = 'https://ssl.reddit.com/api/v1/authorize' access_token_url = 'https://ssl.reddit.com/api/v1/access_token' user_info_url = 'https://oauth.reddit.com/api/v1/me.json' user_info_scope = ['identity'] supported_user_attributes = core.SupportedUserAttributes(id=True, name=True, username=True) def __init__(self, *args, **kwargs): super(Reddit, self).__init__(*args, **kwargs) if self.offline: if not 'duration' in self.user_authorization_params: # http://www.reddit.com/r/changelog/comments/11jab9/reddit_change_permanent_oauth_grants_using/ self.user_authorization_params['duration'] = 'permanent' @classmethod def _x_credentials_parser(cls, credentials, data): if data.get('token_type') == 'bearer': credentials.token_type = cls.BEARER return credentials @staticmethod def _x_user_parser(user, data): user.username = data.get('name') return user
class LinkedIn(OAuth2): """ Linked In |oauth2| provider. .. note:: Doesn't support access token refreshment. * Dashboard: https://www.linkedin.com/secure/developer * Docs: http://developer.linkedin.com/documents/authentication * API reference: http://developer.linkedin.com/rest Supported :class:`.User` properties: * birth_date * country * email * first_name * id * last_name * link * name * phone * picture Unsupported :class:`.User` properties: * city * gender * locale * nickname * postal_code * timezone * username """ user_authorization_url = 'https://www.linkedin.com/uas/oauth2/authorization' access_token_url = 'https://www.linkedin.com/uas/oauth2/accessToken' user_info_url = 'https://api.linkedin.com/v1/people/~:' + \ '(id,first-name,last-name,formatted-name,location,picture-url,public-profile-url,email-address,date-of-birth,phone-numbers)?format=json' user_info_scope = ['r_fullprofile', 'r_emailaddress', 'r_contactinfo'] token_request_method = 'GET' # To avoid a bug with OAuth2.0 on Linkedin # http://developer.linkedin.com/forum/unauthorized-invalid-or-expired-token-immediately-after-receiving-oauth2-token supported_user_attributes = core.SupportedUserAttributes(birth_date=True, country=True, email=True, first_name=True, id=True, last_name=True, link=True, name=True, phone=True, picture=True) @classmethod def _x_request_elements_filter(cls, request_type, request_elements, credentials): if request_type == cls.PROTECTED_RESOURCE_REQUEST_TYPE: # LinkedIn too has it's own terminology! url, method, params, headers, body = request_elements params['oauth2_access_token'] = params.pop('access_token') request_elements = core.RequestElements(url, method, params, headers, body) return request_elements @staticmethod def _x_user_parser(user, data): user.first_name = data.get('firstName') user.last_name = data.get('lastName') user.email = data.get('emailAddress') user.name = data.get('formattedName') user.country = data.get('location', {}).get('name') user.phone = data.get('phoneNumbers', {}).get('values', [{}])[0].get('phoneNumber') user.picture = data.get('pictureUrl') user.link = data.get('publicProfileUrl') _birthdate = data.get('dateOfBirth', {}) if _birthdate: _day = _birthdate.get('day') _month = _birthdate.get('month') _year = _birthdate.get('year') if _day and _month and _year: user.birth_date = datetime.datetime(_year, _month, _day) return user
class Vimeo(OAuth1): """ Vimeo |oauth1| provider. .. warning:: Vimeo needs one more fetch to get rich user info! * Dashboard: https://developer.vimeo.com/apps * Docs: https://developer.vimeo.com/apis/advanced#oauth-endpoints * API reference: https://developer.vimeo.com/apis Supported :class:`.User` properties: * id * link * location * name * picture Unsupported :class:`.User` properties: * birth_date * city * country * email * gender * first_name * last_name * locale * nickname * phone * postal_code * timezone * username """ supported_user_attributes = core.SupportedUserAttributes( id=True, link=True, location=True, name=True, picture=True ) request_token_url = 'https://vimeo.com/oauth/request_token' user_authorization_url = 'https://vimeo.com/oauth/authorize' access_token_url = 'https://vimeo.com/oauth/access_token' user_info_url = ('http://vimeo.com/api/rest/v2?' 'format=json&method=vimeo.oauth.checkAccessToken') def _access_user_info(self): """ Vimeo requires the user ID to access the user info endpoint, so we need to make two requests: one to get user ID and second to get user info. """ response = super(Vimeo, self)._access_user_info() uid = response.data.get('oauth', {}).get('user', {}).get('id') if uid: return self.access('http://vimeo.com/api/v2/{0}/info.json' .format(uid)) return response @staticmethod def _x_user_parser(user, data): user.name = data.get('display_name') user.link = data.get('profile_url') user.picture = data.get('portrait_huge') return user
class Foursquare(OAuth2): """ Foursquare |oauth2| provider. * Dashboard: https://foursquare.com/developers/apps * Docs: https://developer.foursquare.com/overview/auth.html * API reference: https://developer.foursquare.com/docs/ .. note:: Foursquare requires a *version* parameter in each request. The default value is ``v=20140501``. You can override the version in the ``params`` parameter of the :meth:`.Authomatic.access` method. See https://developer.foursquare.com/overview/versioning Supported :class:`.User` properties: * city * country * email * first_name * gender * id * last_name * name * phone * picture Unsupported :class:`.User` properties: * birth_date * link * locale * nickname * postal_code * timezone * username """ user_authorization_url = 'https://foursquare.com/oauth2/authenticate' access_token_url = 'https://foursquare.com/oauth2/access_token' user_info_url = 'https://api.foursquare.com/v2/users/self' same_origin = False supported_user_attributes = core.SupportedUserAttributes(city=True, country=True, email=True, first_name=True, gender=True, id=True, last_name=True, name=True, phone=True, picture=True) @classmethod def _x_request_elements_filter(cls, request_type, request_elements, credentials): if request_type == cls.PROTECTED_RESOURCE_REQUEST_TYPE: # Foursquare uses OAuth 1.0 "oauth_token" for what should be # "access_token" in OAuth 2.0! url, method, params, headers, body = request_elements params['oauth_token'] = params.pop('access_token') # Foursquare needs the version "v" parameter in every request. # https://developer.foursquare.com/overview/versioning if not params.get('v'): params['v'] = '20140501' request_elements = core.RequestElements(url, method, params, headers, body) return request_elements @staticmethod def _x_user_parser(user, data): _resp = data.get('response', {}) _user = _resp.get('user', {}) user.id = _user.get('id') user.first_name = _user.get('firstName') user.last_name = _user.get('lastName') user.gender = _user.get('gender') _photo = _user.get('photo', {}) if isinstance(_photo, dict): _photo_prefix = _photo.get('prefix', '').strip('/') _photo_suffix = _photo.get('suffix', '').strip('/') user.picture = '/'.join([_photo_prefix, _photo_suffix]) if isinstance(_photo, basestring): user.picture = _photo user.city, user.country = _user.get('homeCity', ', ').split(', ') _contact = _user.get('contact', {}) user.email = _contact.get('email') user.phone = _contact.get('phone') return user
class Facebook(OAuth2): """ Facebook |oauth2| provider. * Dashboard: https://developers.facebook.com/apps * Docs: http://developers.facebook.com/docs/howtos/login/server-side-login/ * API reference: http://developers.facebook.com/docs/reference/api/ * API explorer: http://developers.facebook.com/tools/explorer Supported :class:`.User` properties: * city * country * email * first_name * gender * id * last_name * link * locale * name * picture * timezone * username Unsupported :class:`.User` properties: * birth_date * nickname * phone * postal_code """ user_authorization_url = 'https://www.facebook.com/dialog/oauth' access_token_url = 'https://graph.facebook.com/oauth/access_token' user_info_url = 'https://graph.facebook.com/me' user_info_scope = ['user_about_me', 'email'] same_origin = False supported_user_attributes = core.SupportedUserAttributes(id=True, email=True, username=True, name=True, first_name=True, last_name=True, city=True, country=True, gender=True, link=True, locale=True, picture=True, timezone=True) @classmethod def _x_request_elements_filter(cls, request_type, request_elements, credentials): if request_type == cls.REFRESH_TOKEN_REQUEST_TYPE: # As always, Facebook has it's original name for "refresh_token"! url, method, params, headers, body = request_elements params['fb_exchange_token'] = params.pop('refresh_token') params['grant_type'] = 'fb_exchange_token' request_elements = core.RequestElements(url, method, params, headers, body) return request_elements def __init__(self, *args, **kwargs): super(Facebook, self).__init__(*args, **kwargs) # Handle special Facebook requirements to be able to refresh the access token. if self.offline: # Facebook needs an offline_access scope. if not 'offline_access' in self.scope: self.scope.append('offline_access') if self.popup: self.user_authorization_url += '?display=popup' @staticmethod def _x_user_parser(user, data): user.picture = 'http://graph.facebook.com/{0}/picture?type=large'.format( data.get('username')) location = data.get('location', {}).get('name') if location and location.split: split_location = location.split(', ') user.city = split_location[0].strip() if len(split_location) > 1: user.country = split_location[1].strip() return user @staticmethod def _x_credentials_parser(credentials, data): """ We need to override this method to fix Facebooks naming deviation. """ # Facebook returns "expires" instead of "expires_in". credentials.expire_in = data.get('expires') return credentials @staticmethod def _x_refresh_credentials_if(credentials): # Always refresh. return True
class VK(OAuth2): """ VK.com |oauth2| provider. * Dashboard: Could not find any. You must do it like this: http://vk.com/editapp?id={consumer_key} * Docs: http://vk.com/developers.php?oid=-17680044&p=Authorizing_Sites * API reference: http://vk.com/developers.php?oid=-17680044&p=API_Method_Description .. note:: VK uses a `bitmask scope <http://vk.com/developers.php?oid=-17680044&p=Application_Rights>`_! Use it like this: .. code-block:: python :emphasize-lines: 7 CONFIG = { 'vk': { 'class_': oauth2.VK, 'consumer_key': '#####', 'consumer_secret': '#####', 'id': authomatic.provider_id(), 'scope': ['1024'] # Always a single item. } } Supported :class:`.User` properties: * birth_date * city * country * first_name * gender * id * last_name * name * picture * timezone Unsupported :class:`.User` properties: * email * link * locale * nickname * phone * postal_code * username """ user_authorization_url = 'http://api.vkontakte.ru/oauth/authorize' access_token_url = 'https://api.vkontakte.ru/oauth/access_token' user_info_url = 'https://api.vk.com/method/getProfiles?' + \ 'fields=uid,first_name,last_name,nickname,sex,bdate,city,country,timezone,photo_big' supported_user_attributes = core.SupportedUserAttributes( birth_date=True, city=True, country=True, first_name=True, gender=True, id=True, last_name=True, name=True, picture=True, timezone=True, ) def __init__(self, *args, **kwargs): super(VK, self).__init__(*args, **kwargs) if self.offline: if not 'offline' in self.scope: self.scope.append('offline') @staticmethod def _x_user_parser(user, data): _resp = data.get('response', [{}])[0] _birth_date = _resp.get('bdate') if _birth_date: user.birth_date = datetime.datetime.strptime( _birth_date, '%d.%m.%Y') user.id = _resp.get('uid') user.first_name = _resp.get('first_name') user.gender = _resp.get('sex') user.last_name = _resp.get('last_name') user.nickname = _resp.get('nickname') user.city = _resp.get('city') user.country = _resp.get('country') user.timezone = _resp.get('timezone') user.picture = _resp.get('photo_big') return user
class Bitly(OAuth2): """ Bitly |oauth2| provider. .. warning:: |no-csrf| * Dashboard: https://bitly.com/a/oauth_apps * Docs: http://dev.bitly.com/authentication.html * API reference: http://dev.bitly.com/api.html Supported :class:`.User` properties: * id * link * name * picture * username Unsupported :class:`.User` properties: * birth_date * city * country * email * first_name * gender * last_name * locale * nickname * phone * postal_code * timezone """ supported_user_attributes = core.SupportedUserAttributes(id=True, link=True, name=True, picture=True, username=True) supports_csrf_protection = False _x_use_authorization_header = False user_authorization_url = 'https://bitly.com/oauth/authorize' access_token_url = 'https://api-ssl.bitly.com/oauth/access_token' user_info_url = 'https://api-ssl.bitly.com/v3/user/info' def __init__(self, *args, **kwargs): super(Bitly, self).__init__(*args, **kwargs) if self.offline: if not 'grant_type' in self.access_token_params: self.access_token_params['grant_type'] = 'refresh_token' @staticmethod def _x_user_parser(user, data): info = data.get('data', {}) user.id = info.get('login') user.name = info.get('full_name') user.username = info.get('display_name') user.picture = info.get('profile_image') user.link = info.get('profile_url') return user
class Xero(OAuth1): """ Xero |oauth1| provider. .. note:: API returns XML! * Dashboard: https://api.xero.com/Application * Docs: http://blog.xero.com/developer/api-overview/public-applications/ * API reference: http://blog.xero.com/developer/api/ Supported :class:`.User` properties: * email * first_name * id * last_name * name Unsupported :class:`.User` properties: * birth_date * city * country * gender * link * locale * location * nickname * phone * picture * postal_code * timezone * username """ supported_user_attributes = core.SupportedUserAttributes( email=True, first_name=True, id=True, last_name=True, name=True ) request_token_url = 'https://api.xero.com/oauth/RequestToken' user_authorization_url = 'https://api.xero.com/oauth/Authorize' access_token_url = 'https://api.xero.com/oauth/AccessToken' user_info_url = 'https://api.xero.com/api.xro/2.0/Users' @staticmethod def _x_user_parser(user, data): # Data is xml.etree.ElementTree.Element object. if type(data) is not dict: # But only on user.update() _user = data.find('Users/User') user.id = _user.find('UserID').text user.first_name = _user.find('FirstName').text user.last_name = _user.find('LastName').text user.email = _user.find('EmailAddress').text return user
class Google(OAuth2): """ Google |oauth2| provider. * Dashboard: https://console.developers.google.com/project * Docs: https://developers.google.com/accounts/docs/OAuth2 * API reference: https://developers.google.com/gdata/docs/directory * API explorer: https://developers.google.com/oauthplayground/ Supported :class:`.User` properties: * email * first_name * gender * id * last_name * link * locale * name * picture Unsupported :class:`.User` properties: * birth_date * city * country * nickname * phone * postal_code * timezone * username """ user_authorization_url = 'https://accounts.google.com/o/oauth2/auth' access_token_url = 'https://accounts.google.com/o/oauth2/token' user_info_url = 'https://www.googleapis.com/plus/v1/people/me' user_info_scope = ['profile', 'email'] supported_user_attributes = core.SupportedUserAttributes(id=True, email=True, name=True, first_name=True, last_name=True, gender=True, locale=True, link=True, picture=True) def __init__(self, *args, **kwargs): super(Google, self).__init__(*args, **kwargs) # Handle special Google requirements to be able to refresh the access token. if self.offline: if not 'access_type' in self.user_authorization_params: # Google needs access_type=offline param in the user authorization request. self.user_authorization_params['access_type'] = 'offline' if not 'approval_prompt' in self.user_authorization_params: # And also approval_prompt=force. self.user_authorization_params['approval_prompt'] = 'force' @staticmethod def _x_user_parser(user, data): emails = data.get('emails', []) if emails: user.email = emails[0].get('value') for email in emails: if email.get('type') == 'account': user.email = email.get('value') break user.id = data.get('sub') or data.get('id') user.name = data.get('displayName') user.first_name = data.get('name', {}).get('givenName') user.last_name = data.get('name', {}).get('familyName') user.locale = data.get('language') user.link = data.get('url') user.picture = data.get('image', {}).get('url') try: user.birth_date = datetime.datetime.strptime( data.get('birthdate'), "%Y-%m-%d") except: user.birth_date = data.get('birthdate') return user def _x_scope_parser(self, scope): """ Google has space-separated scopes """ return ' '.join(scope)
class Google(OAuth2): """ Google |oauth2| provider. * Dashboard: https://console.developers.google.com/project * Docs: https://developers.google.com/accounts/docs/OAuth2 * API reference: https://developers.google.com/gdata/docs/directory * API explorer: https://developers.google.com/oauthplayground/ Supported :class:`.User` properties: * email * first_name * gender * id * last_name * link * locale * name * picture Unsupported :class:`.User` properties: * birth_date * city * country * nickname * phone * postal_code * timezone * username .. note:: To get the user info, you need to activate the **Google+ API** in the **APIs & auth >> APIs** section of the`Google Developers Console <https://console.developers.google.com/project>`__. """ user_authorization_url = 'https://accounts.google.com/o/oauth2/auth' access_token_url = 'https://accounts.google.com/o/oauth2/token' user_info_url = 'https://www.googleapis.com/oauth2/v3/userinfo?alt=json' user_info_scope = ['profile', 'email'] supported_user_attributes = core.SupportedUserAttributes( id=False, email=True, name=True, first_name=True, last_name=True, locale=True, picture=True, # No longer supported as of 2016-08 link=False, gender=False, ) def __init__(self, *args, **kwargs): super(Google, self).__init__(*args, **kwargs) # Handle special Google requirements to be able to refresh the access token. if self.offline: if not 'access_type' in self.user_authorization_params: # Google needs access_type=offline param in the user authorization request. self.user_authorization_params['access_type'] = 'offline' if not 'approval_prompt' in self.user_authorization_params: # And also approval_prompt=force. self.user_authorization_params['approval_prompt'] = 'force' @classmethod def _x_request_elements_filter(cls, request_type, request_elements, credentials): """ Google doesn't accept client ID and secret to be at the same time in request parameters and in the basic authorization header in the access token request. """ if request_type is cls.ACCESS_TOKEN_REQUEST_TYPE: params = request_elements[2] del params['client_id'] del params['client_secret'] return request_elements @staticmethod def _x_user_parser(user, data): user.email = data.get('email') user.name = data.get('name') user.first_name = data.get('given_name', '') user.last_name = data.get('family_name', '') user.locale = data.get('locale', '') user.picture = data.get('picture', '') # Special attribute if email has been verified user.email_verified = data.get("email_verified") user.hosted_domain = data.get("hd") return user def _x_scope_parser(self, scope): """ Google has space-separated scopes """ return ' '.join(scope)
class Bitbucket(OAuth1): """ Bitbucket |oauth1| provider. * Dashboard: https://bitbucket.org/account/user/peterhudec/api * Docs: https://confluence.atlassian.com/display/BITBUCKET/oauth+Endpoint * API reference: https://confluence.atlassian.com/display/BITBUCKET/Using+the+Bitbucket+REST+APIs Supported :class:`.User` properties: * first_name * id * last_name * link * name * picture * username * email Unsupported :class:`.User` properties: * birth_date * city * country * gender * locale * location * nickname * phone * postal_code * timezone .. note:: To get the full user info, you need to select both the *Account Read* and the *Repositories Read* permission in the Bitbucket application edit form. """ supported_user_attributes = core.SupportedUserAttributes(first_name=True, id=True, last_name=True, link=True, name=True, picture=True, username=True, email=True) request_token_url = 'https://bitbucket.org/!api/1.0/oauth/request_token' user_authorization_url = 'https://bitbucket.org/!api/1.0/oauth/' + \ 'authenticate' access_token_url = 'https://bitbucket.org/!api/1.0/oauth/access_token' user_info_url = 'https://api.bitbucket.org/1.0/user' user_email_url = 'https://api.bitbucket.org/1.0/emails' @staticmethod def _x_user_parser(user, data): _user = data.get('user', {}) user.username = user.id = _user.get('username') user.name = _user.get('display_name') user.first_name = _user.get('first_name') user.last_name = _user.get('last_name') user.picture = _user.get('avatar') user.link = 'https://bitbucket.org/api{0}'\ .format(_user.get('resource_uri')) return user def _access_user_info(self): """ Email is available in separate method so second request is needed. """ response = super(Bitbucket, self)._access_user_info() response.data.setdefault("email", None) email_response = self.access(self.user_email_url) if email_response.data: for item in email_response.data: if item.get("primary", False): response.data.update(email=item.get("email", None)) return response