def get(self): code = util.get_required_param(self, 'code') state = util.decode_oauth_state(util.get_required_param(self, 'state')) endpoint = state.get('endpoint') me = state.get('me') if not endpoint or not me: raise exc.HTTPBadRequest("invalid state parameter") state = state.get('state') or '' validate_resp = util.requests_post(endpoint, data={ 'me': me, 'client_id': appengine_config.INDIEAUTH_CLIENT_ID, 'code': code, 'redirect_uri': self.request.path_url, 'state': state, }) if validate_resp.status_code // 100 == 2: data = util.sniff_json_or_form_encoded(validate_resp.content) if data.get('me'): verified = data.get('me') user_json = build_user_json(verified) indie_auth = IndieAuth(id=verified, user_json=json.dumps(user_json)) indie_auth.put() self.finish(indie_auth, state=state) else: raise exc.HTTPBadRequest( 'Verification response missing required "me" field') else: raise exc.HTTPBadRequest('IndieAuth verification failed: %s %s' % (validate_resp.status_code, validate_resp.text))
def redirect_url(self, state=None, me=None): assert appengine_config.INDIEAUTH_CLIENT_ID, ( "Please fill in the indieauth_client_id in your app's root directory.") if not me: me = util.get_required_param(self, 'me') parsed = urlparse.urlparse(me) if not parsed.scheme: me = 'http://' + me redirect_uri = self.to_url() endpoint = discover_authorization_endpoint(me) url = endpoint + '?' + urllib.urlencode({ 'me': me, 'client_id': appengine_config.INDIEAUTH_CLIENT_ID, 'redirect_uri': redirect_uri, 'state': util.encode_oauth_state({ 'endpoint': endpoint, 'me': me, 'state': state, }), }) logging.info('Redirecting to IndieAuth: %s', url) return str(url)
def get(self): # handle errors error = self.request.get('error') if error: if error == 'access_denied': logging.info('User declined') self.finish(None, state=self.request.get('state')) return else: raise exc.HTTPBadRequest('Error: %s' % error) # extract auth code and request access token auth_code = util.get_required_param(self, 'code') data = { 'code': auth_code, 'client_id': appengine_config.MEDIUM_CLIENT_ID, 'client_secret': appengine_config.MEDIUM_CLIENT_SECRET, # redirect_uri here must be the same in the oauth code request! # (the value here doesn't actually matter since it's requested server side.) 'redirect_uri': self.request.path_url, 'grant_type': 'authorization_code', } resp = util.requests_post(GET_ACCESS_TOKEN_URL, data=urllib.urlencode(data), headers={ 'User-Agent': USER_AGENT }).text logging.debug('Access token response: %s', resp) try: resp = json.loads(resp) except: logging.exception('Could not decode JSON') raise errors = resp.get('errors') or resp.get('error') if errors: logging.info('Errors: %s', errors) raise exc.HTTPBadRequest(errors[0].get('message')) # TODO: handle refresh token access_token = resp['access_token'] user_json = MediumAuth( access_token_str=access_token).get(API_USER_URL).text id = json.loads(user_json)['data']['id'] auth = MediumAuth(id=id, access_token_str=access_token, user_json=user_json) auth.put() self.finish(auth, state=self.request.get('state'))
def get(self): state = util.get_required_param(self, 'state') # handle errors error = self.request.get('error') error_reason = urllib.unquote_plus(self.request.get('error_reason', '')) if error or error_reason: if error == 'access_denied': logging.info('User declined: %s', error_reason) self.finish(None, state=state) return else: raise exc.HTTPBadRequest(' '.join((error, error_reason))) # lookup the CSRF token try: csrf_id = int(urllib.unquote_plus(state).split('|')[-1]) except (ValueError, TypeError): raise exc.HTTPBadRequest('Invalid state value %r' % state) csrf = DropboxCsrf.get_by_id(csrf_id) if not csrf: raise exc.HTTPBadRequest('No CSRF token for id %s' % csrf_id) # request an access token data = { 'client_id': appengine_config.DROPBOX_APP_KEY, 'client_secret': appengine_config.DROPBOX_APP_SECRET, 'code': util.get_required_param(self, 'code'), 'redirect_uri': self.request.path_url, } try: resp = util.urlopen(GET_ACCESS_TOKEN_URL % data, data='').read() except BaseException, e: util.interpret_http_exception(e) raise
def get(self): if CallbackHandler.handle_error(self): return auth_code = util.get_required_param(self, 'code') url = GET_ACCESS_TOKEN_URL % { 'auth_code': auth_code, 'client_id': appengine_config.FACEBOOK_APP_ID, 'client_secret': appengine_config.FACEBOOK_APP_SECRET, 'redirect_uri': urllib.quote_plus(self.request.path_url), } try: resp = json.loads(util.urlopen(url).read()) except urllib2.HTTPError, e: logging.error(e.read()) raise
def get(self): # handle errors error = self.request.get('error') if error: if error == 'access_denied': logging.info('User declined') self.finish(None, state=self.request.get('state')) return else: msg = 'Error: %s: %s' % (error, self.request.get('error_description')) logging.info(msg) raise exc.HTTPBadRequest(msg) # extract auth code and request access token auth_code = util.get_required_param(self, 'code') data = { 'code': auth_code, 'client_id': appengine_config.GITHUB_CLIENT_ID, 'client_secret': appengine_config.GITHUB_CLIENT_SECRET, # redirect_uri here must be the same in the oauth code request! # (the value here doesn't actually matter since it's requested server side.) 'redirect_uri': self.request.path_url, } resp = util.requests_post(GET_ACCESS_TOKEN_URL, data=urllib.urlencode(data)).text logging.debug('Access token response: %s', resp) resp = urlparse.parse_qs(resp) error = resp.get('error') if error: msg = 'Error: %s: %s' % (error[0], resp.get('error_description')) logging.info(msg) raise exc.HTTPBadRequest(msg) access_token = resp['access_token'][0] resp = GitHubAuth(access_token_str=access_token).post( API_GRAPHQL, json=GRAPHQL_USER).json() logging.debug('GraphQL data.viewer response: %s', resp) user_json = resp['data']['viewer'] auth = GitHubAuth(id=user_json['login'], access_token_str=access_token, user_json=json.dumps(user_json)) auth.put() self.finish(auth, state=self.request.get('state'))
def get(self): # handle errors error = self.request.get('error') if error: error_description = urllib.unquote_plus( self.request.get('error_description', '')) if error == 'access_denied': logging.info('User declined: %s', error_description) self.finish(None, state=self.request.get('state')) return else: raise exc.HTTPBadRequest('Error: %s %s ' % (error, error_description)) # extract auth code and request access token auth_code = util.get_required_param(self, 'code') data = { 'code': auth_code, 'client_id': appengine_config.WORDPRESS_CLIENT_ID, 'client_secret': appengine_config.WORDPRESS_CLIENT_SECRET, # redirect_uri here must be the same in the oauth code request! # (the value here doesn't actually matter since it's requested server side.) 'redirect_uri': self.request.path_url, 'grant_type': 'authorization_code', } resp = util.urlopen(GET_ACCESS_TOKEN_URL, data=urllib.urlencode(data)).read() logging.debug('Access token response: %s', resp) try: resp = json.loads(resp) blog_id = resp['blog_id'] blog_url = resp['blog_url'] blog_domain = util.domain_from_link(resp['blog_url']) access_token = resp['access_token'] except: logging.exception('Could not decode JSON') raise auth = WordPressAuth(id=blog_domain, blog_id=blog_id, blog_url=blog_url, access_token_str=access_token) auth.user_json = auth.urlopen(API_USER_URL).read() auth.put() self.finish(auth, state=self.request.get('state'))
def get(self): # handle errors error = self.request.get('error') if error: if error == 'access_denied': logging.info('User declined') self.finish(None, state=self.request.get('state')) return else: raise exc.HTTPBadRequest('Error: %s' % error) # extract auth code and request access token auth_code = util.get_required_param(self, 'code') data = { 'code': auth_code, 'client_id': appengine_config.MEDIUM_CLIENT_ID, 'client_secret': appengine_config.MEDIUM_CLIENT_SECRET, # redirect_uri here must be the same in the oauth code request! # (the value here doesn't actually matter since it's requested server side.) 'redirect_uri': self.request.path_url, 'grant_type': 'authorization_code', } resp = util.requests_post( GET_ACCESS_TOKEN_URL, data=urllib.urlencode(data), headers={'User-Agent': USER_AGENT}).text logging.debug('Access token response: %s', resp) try: resp = json.loads(resp) except: logging.exception('Could not decode JSON') raise errors = resp.get('errors') or resp.get('error') if errors: logging.info('Errors: %s', errors) raise exc.HTTPBadRequest(errors[0].get('message')) # TODO: handle refresh token access_token = resp['access_token'] user_json = MediumAuth(access_token_str=access_token).get(API_USER_URL).text id = json.loads(user_json)['data']['id'] auth = MediumAuth(id=id, access_token_str=access_token, user_json=user_json) auth.put() self.finish(auth, state=self.request.get('state'))
def get(self): if self.handle_error(): return # https://disqus.com/api/docs/auth/ auth_code = util.get_required_param(self, 'code') data = { 'grant_type': 'authorization_code', 'client_id': appengine_config.DISQUS_CLIENT_ID, 'client_secret': appengine_config.DISQUS_CLIENT_SECRET, 'redirect_uri': self.request_url_with_state(), 'code': auth_code, } resp = util.urlopen(GET_ACCESS_TOKEN_URL, data=urllib.urlencode(data)).read() try: data = json.loads(resp) except (ValueError, TypeError): logging.exception('Bad response:\n%s', resp) raise exc.HttpBadRequest( 'Bad Disqus response to access token request') access_token = data['access_token'] user_id = data['user_id'] # TODO is a username key preferred? # username = data['username'] auth = DisqusAuth(id=str(user_id), auth_code=auth_code, access_token_str=access_token) resp = auth.urlopen(USER_DETAILS_URL % user_id).read() try: user_data = json.loads(resp)['response'] except (ValueError, TypeError): logging.exception('Bad response:\n%s', resp) raise exc.HttpBadRequest( 'Bad Disqus response to user details request') auth.user_json = json.dumps(user_data) logging.info('created disqus auth %s', auth) auth.put() self.finish(auth, state=self.request.get('state'))
def get(self): if facebook.CallbackHandler.handle_error(self): return # http://instagram.com/developer/authentication/ auth_code = util.get_required_param(self, 'code') data = { 'client_id': appengine_config.INSTAGRAM_CLIENT_ID, 'client_secret': appengine_config.INSTAGRAM_CLIENT_SECRET, 'code': auth_code, 'redirect_uri': self.request_url_with_state(), 'grant_type': 'authorization_code', } try: resp = util.urlopen(GET_ACCESS_TOKEN_URL, data=urllib.urlencode(data)).read() except BaseException, e: util.interpret_http_exception(e) raise
def get(self): if self.handle_error(): return # https://disqus.com/api/docs/auth/ auth_code = util.get_required_param(self, 'code') data = { 'grant_type': 'authorization_code', 'client_id': appengine_config.DISQUS_CLIENT_ID, 'client_secret': appengine_config.DISQUS_CLIENT_SECRET, 'redirect_uri': self.request_url_with_state(), 'code': auth_code, } resp = util.urlopen(GET_ACCESS_TOKEN_URL, data=urllib.urlencode(data)).read() try: data = json.loads(resp) except (ValueError, TypeError): logging.exception('Bad response:\n%s', resp) raise exc.HttpBadRequest('Bad Disqus response to access token request') access_token = data['access_token'] user_id = data['user_id'] # TODO is a username key preferred? # username = data['username'] auth = DisqusAuth(id=str(user_id), auth_code=auth_code, access_token_str=access_token) resp = auth.urlopen(USER_DETAILS_URL % user_id).read() try: user_data = json.loads(resp)['response'] except (ValueError, TypeError): logging.exception('Bad response:\n%s', resp) raise exc.HttpBadRequest('Bad Disqus response to user details request') auth.user_json = json.dumps(user_data) logging.info('created disqus auth %s', auth) auth.put() self.finish(auth, state=self.request.get('state'))
def get(self): # handle errors error = self.request.get('error') desc = self.request.get('error_description') if error: # https://docs.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow?context=linkedin/consumer/context#application-is-rejected if error in ('user_cancelled_login', 'user_cancelled_authorize'): logging.info('User declined: %s', self.request.get('error_description')) self.finish(None, state=self.request.get('state')) return else: msg = 'Error: %s: %s' % (error, desc) logging.info(msg) raise exc.HTTPBadRequest(msg) # extract auth code and request access token auth_code = util.get_required_param(self, 'code') data = { 'grant_type': 'authorization_code', 'code': auth_code, 'client_id': appengine_config.LINKEDIN_CLIENT_ID, 'client_secret': appengine_config.LINKEDIN_CLIENT_SECRET, # redirect_uri here must be the same in the oauth code request! # (the value here doesn't actually matter since it's requested server side.) 'redirect_uri': self.request.path_url, } resp = util.requests_post(ACCESS_TOKEN_URL, data=urllib.urlencode(data)).json() logging.debug('Access token response: %s', resp) if resp.get('serviceErrorCode'): msg = 'Error: %s' % resp logging.info(msg) raise exc.HTTPBadRequest(msg) access_token = resp['access_token'] resp = LinkedInAuth(access_token_str=access_token).get(API_PROFILE_URL).json() logging.debug('Profile response: %s', resp) auth = LinkedInAuth(id=resp['id'], access_token_str=access_token, user_json=json.dumps(resp)) auth.put() self.finish(auth, state=self.request.get('state'))