def test_auto_refresh_token2(self): def _update_token(token, refresh_token=None, access_token=None): self.assertEqual(access_token, 'a') self.assertEqual(token, self.token) update_token = mock.Mock(side_effect=_update_token) old_token = dict(access_token='a', token_type='bearer', expires_at=100) sess = OAuth2Session( 'foo', token=old_token, token_endpoint='https://i.b/token', grant_type='client_credentials', ) sess.send = mock_json_response(self.token) sess.get('https://i.b/user') self.assertFalse(update_token.called) sess = OAuth2Session( 'foo', token=old_token, token_endpoint='https://i.b/token', grant_type='client_credentials', update_token=update_token, ) sess.send = mock_json_response(self.token) sess.get('https://i.b/user') self.assertTrue(update_token.called)
def authorize(): client_id = os.getenv('GOOGLE_CLIENT_ID') client_secret = os.getenv('GOOGLE_CLIENT_SECRET') token = request.json.get("token") client = OAuth2Session(client_id, client_secret, token=token) account_url = 'https://www.googleapis.com/oauth2/v2/userinfo' client = OAuth2Session(client_id, client_secret, token=token) resp = client.get(account_url) username = resp.json()['name'] email = resp.json()['email'] user = User.get_or_none(User.email == email) if user: token = create_access_token(identity=user.id) return jsonify({"token": token}) else: password = os.urandom(8) hashed_password = generate_password_hash(password) create_user = User(username=username, email=email, hashed_password=hashed_password) create_user.save() token = create_access_token(identity=create_user.id, expires_delta=False) return jsonify({"token": token})
def test_fetch_token_post(self): url = 'https://example.com/token' def fake_send(r, **kwargs): self.assertIn('code=v', r.body) self.assertIn('client_id=', r.body) self.assertIn('grant_type=authorization_code', r.body) resp = mock.MagicMock() resp.json = lambda: self.token return resp sess = OAuth2Session(client_id=self.client_id) sess.send = fake_send self.assertEqual( sess.fetch_token(url, authorization_response='https://i.b/?code=v'), self.token) sess = OAuth2Session( client_id=self.client_id, token_endpoint_auth_method='none', ) sess.send = fake_send token = sess.fetch_token(url, code='v') self.assertEqual(token, self.token) error = {'error': 'invalid_request'} sess = OAuth2Session(client_id=self.client_id, token=self.token) sess.send = mock_json_response(error) self.assertRaises(OAuthError, sess.fetch_access_token, url)
def test_fetch_token_get(self): url = 'https://example.com/token' def fake_send(r, **kwargs): self.assertIn('code=v', r.url) self.assertIn('grant_type=authorization_code', r.url) resp = mock.MagicMock() resp.json = lambda: self.token return resp sess = OAuth2Session(client_id=self.client_id) sess.send = fake_send token = sess.fetch_token(url, authorization_response='https://i.b/?code=v', method='GET') self.assertEqual(token, self.token) sess = OAuth2Session( client_id=self.client_id, token_endpoint_auth_method='none', ) sess.send = fake_send token = sess.fetch_token(url, code='v', method='GET') self.assertEqual(token, self.token) token = sess.fetch_token(url + '?q=a', code='v', method='GET') self.assertEqual(token, self.token)
def authorization_code_flow(): # https://codeloop.org/django-social-login-authentication-example/ # https://docs.authlib.org/en/stable/client/oauth2.html # https://www.oauth.com/oauth2-servers/server-side-apps/example-flow/ # https://docs.github.com/en/free-pro-team@latest/developers/apps/scopes-for-oauth-apps # https://www.youtube.com/watch?v=m5sHDaBwxjc client_id = '061cc79cf9983a3b71c6' client_secret = '1b15d05e0f440d393f5b9e78953b45479bdaee93' scope = 'user:email' # we want to fetch user's email # scope = 'user public_repo' # using requests implementation from authlib.integrations.requests_client import OAuth2Session client = OAuth2Session(client_id, client_secret, scope=scope) # print(dir(client),client.token_auth,'--->see') # using httpx implementation # from authlib.integrations.httpx_client import AsyncOAuth2Client # client = AsyncOAuth2Client(client_id, client_secret, scope=scope) # Unlike OAuth 1, there is no request token. The first step is to jump to the remote authorization server: # The create_authorization_url returns a tuple of (uri, state), in real project, you should save the state for later use. authorization_endpoint = 'https://github.com/login/oauth/authorize' uri, state = client.create_authorization_url(authorization_endpoint) print(uri, '-->uri') # https://github.com/login/oauth/authorize?response_type=code&client_id=061cc79cf9983a3b71c6&scope=user+public_repo&state=byalzWy9PjL6tPNRc1YSC3HPicDqYt # if cancel # https://www.google.com/?error=access_denied&error_description=The+user+has+denied+your+application+access.&error_uri=https%3A%2F%2Fdocs.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23access-denied&state=jwOA06wTrrMXRBXpwy8iRYD1Yuasrt # after that just copy above uri and paste it in browser,u will get bellow authorization_response url # authorization_response = 'https://www.google.com/?code=c1fcd5445035d9c1152e&state=pojk9RyDmfLHljJPYEiZd8JBCOkFZd' authorization_response = 'https://www.google.com/?code=b281d6b3129ac7125345&state=byalzWy9PjL6tPNRc1YSC3HPicDqYt' token_endpoint = 'https://github.com/login/oauth/access_token' # token = client.fetch_token(token_endpoint, authorization_response=authorization_response) # token={'access_token': 'd0b99754172aee541bb3fedb409f5759692900e8', 'token_type': 'bearer', 'scope': 'user:email'} token = { 'access_token': '04014f6f1cfe33c958b728d96f977c7b42bcca53', 'token_type': 'bearer', 'scope': 'public_repo,user' } print(token) client = OAuth2Session(client_id, client_secret, token=token) account_url = 'https://api.github.com/user' resp = client.get(account_url) pprint(resp.json(), indent=4)
def test_custom_client_auth_method(self): def auth_client(client, method, uri, headers, body): uri = add_params_to_uri(uri, [ ('client_id', client.client_id), ('client_secret', client.client_secret), ]) uri = uri + '&' + body body = '' return uri, headers, body sess = OAuth2Session('id', 'secret', token_endpoint_auth_method='client_secret_uri') sess.register_client_auth_method(('client_secret_uri', auth_client)) def fake_send(r, **kwargs): self.assertIn('client_id=', r.url) self.assertIn('client_secret=', r.url) resp = mock.MagicMock() resp.json = lambda: self.token return resp sess.send = fake_send token = sess.fetch_token('https://i.b/token') self.assertEqual(token, self.token)
def test_missing_token(self): sess = OAuth2Session('foo') self.assertRaises( OAuthError, sess.get, 'https://i.b/token', )
def google(path): session = OAuth2Session(environ.get('GOOGLE_CLIENT_ID'), environ.get('GOOGLE_CLIENT_SECRET'), redirect_uri=environ.get('GOOGLE_REDIRECT_URI'), scope=environ.get('GOOGLE_SCOPE')) authorization_url, state = session.create_authorization_url('https://accounts.google.com/o/oauth2/auth') return {'authorization_url': authorization_url}
def __init__(self, *, auth=None, client_id: Optional[str] = None, client_secret: Optional[str] = None, host: str = DEFAULT_HOST): """ There is a variety of ways to setup the authentication. See https://github.com/annotell/annotell-python/tree/master/annotell-auth :param auth: authentication credentials :param client_id: client id for authentication :param client_secret: client secret for authentication :param host: base url for authentication server """ self.host = host self.token_url = "%s/v1/auth/oauth/token" % self.host client_id, client_secret = resolve_credentials(auth, client_id, client_secret) self.oauth_session = OAuth2Session( client_id=client_id, client_secret=client_secret, token_endpoint_auth_method='client_secret_post', update_token=self._update_token, token_endpoint=self.token_url) self._token = None self._expires_at = None self._lock = threading.RLock()
def authorized(): if "error" in request.args: # User cancelled the auth flow - discard auth (most likely there won't be any) session.pop("twitch_token", None) return redirect(url_for("mainpage")) twitch = OAuth2Session(config.CLIENT_ID, config.CLIENT_SECRET, state=session["login_state"]) resp = twitch.fetch_access_token( "https://id.twitch.tv/oauth2/token", code=request.args["code"], # For some bizarre reason, we need to pass this information along. client_id=config.CLIENT_ID, client_secret=config.CLIENT_SECRET, redirect_uri=url_for("authorized", _external=True)) if "access_token" not in resp: # Something went wrong with the retrieval. No idea what or why, # so I'm doing a cop-out and just dumping to console. print("Unable to log in") pprint(resp) print("Returning generic failure.") raise Exception session["twitch_token"] = resp["access_token"] session["twitch_refresh_token"] = resp["refresh_token"] session["twitch_auth_scopes"] = " ".join(sorted(resp["scope"])) user = query("helix/users", token="bearer")["data"][0] user["_id"] = user[ "id"] # For now, everything looks for _id. Existing logins don't have user["id"]. database.create_user(user["_id"]) session["twitch_user"] = user return redirect(url_for("mainpage"))
def test_revoke_token(self): sess = OAuth2Session('a') answer = {'status': 'ok'} sess.send = mock_json_response(answer) resp = sess.revoke_token('https://i.b/token', 'hi') self.assertEqual(resp.json(), answer) resp = sess.revoke_token( 'https://i.b/token', 'hi', token_type_hint='access_token' ) self.assertEqual(resp.json(), answer) def revoke_token_request(url, headers, data): self.assertEqual(url, 'https://i.b/token') return url, headers, data sess.register_compliance_hook( 'revoke_token_request', revoke_token_request, ) sess.revoke_token( 'https://i.b/token', 'hi', body='', token_type_hint='access_token' )
def discord(path): session = OAuth2Session(environ.get('DISCORD_CLIENT_ID'), environ.get('DISCORD_CLIENT_SECRET'), redirect_uri=environ.get('DISCORD_REDIRECT_URI'), scope=environ.get('DISCORD_SCOPE')) authorization_url, state = session.create_authorization_url('https://discord.com/api/oauth2/authorize') return {'authorization_url': authorization_url}
def test_create_authorization_url(self): url = 'https://example.com/authorize?foo=bar' sess = OAuth2Session(client_id=self.client_id) auth_url, state = sess.create_authorization_url(url) self.assertIn(state, auth_url) self.assertIn(self.client_id, auth_url) self.assertIn('response_type=code', auth_url) sess = OAuth2Session(client_id=self.client_id, prompt='none') auth_url, state = sess.create_authorization_url( url, state='foo', redirect_uri='https://i.b', scope='profile') self.assertEqual(state, 'foo') self.assertIn('i.b', auth_url) self.assertIn('profile', auth_url) self.assertIn('prompt=none', auth_url)
def google_auth_redirect(): req_state = flask.request.args.get('state', default=None, type=None) print((flask.session).keys()) if req_state != flask.session[AUTH_STATE_KEY]: response = flask.make_response('Invalid state parameter', 401) return response session = OAuth2Session(CLIENT_ID, CLIENT_SECRET, scope=AUTHORIZATION_SCOPE, state=flask.session[AUTH_STATE_KEY], redirect_uri=AUTH_REDIRECT_URI) oauth2_tokens = session.fetch_access_token( ACCESS_TOKEN_URI, authorization_response=flask.request.url) flask.session[AUTH_TOKEN_KEY] = oauth2_tokens info = get_user_info() users_email = info["email"] users_name = info["given_name"] lname = info["family_name"] user = User.query.filter_by(email=users_email).first() if not user: user = User(fname=users_name, email=users_email, lname=lname) db.session.add(user) db.session.commit() return flask.redirect(BASE_URI, code=302)
def fetch_token(self): # enable dynamic refresh only if the identity # has been already stored in the database if inspect(self).persistent: # fetch up to date identity data self.refresh() # reference to the token associated with the identity instance token = self.token # the token should be refreshed # if it is expired or close to expire (i.e., n secs before expiration) if token.to_be_refreshed(): if 'refresh_token' not in token: logger.debug( "The token should be refreshed but no refresh token is associated with the token" ) else: logger.debug("Trying to refresh the token...") oauth2session = OAuth2Session(self.provider.client_id, self.provider.client_secret, token=self.token) new_token = oauth2session.refresh_token( self.provider.access_token_url, refresh_token=token['refresh_token']) self.token = new_token self.save() logger.debug("User token updated") logger.debug("Using token %r", self.token) return self.token
def google_login(): from app import Users, db state = None while state is None: google_session = OAuth2Session(CLIENT_ID, CLIENT_SECRET, scope=AUTHORIZATION_SCOPE, redirect_uri=AUTH_REDIRECT_URI) uri, state = google_session.create_authorization_url(AUTHORIZATION_URL) flask.session[AUTH_STATE_KEY] = state print(f"\n\nGoogle Auth State: \n\n{state}\n\n") # flask.session.permanent = True try: user_info = get_user_info() email = user_info['email'] user = Users.query.filter_by(email=email).first() print(f"\n\n\n{user}\n\n\n") if user is None: user = Users(email=user_info['email'], name=user_info['name'], avatar=user_info['picture']) db.session.add(user) db.session.commit() except: return flask.redirect(uri, code=302) return flask.redirect(uri, code=200)
def search_mainstay_files(credentials): graph_client = OAuth2Session(token=credentials) graph_path = '/me/drive/root:/Mainstay:/children' response = graph_client.get(f"{graph_url}{graph_path}").json() ofiles = get_files_list(response) return ofiles
def login(): twitch = OAuth2Session(config.CLIENT_ID, config.CLIENT_SECRET, scope="") uri, state = twitch.create_authorization_url("https://id.twitch.tv/oauth2/authorize", redirect_uri=os.environ.get("OVERRIDE_REDIRECT_URI") or url_for("authorized", _external=True)) session["login_state"] = state return redirect(uri)
class StravaAccountAPICalls(OAuthMixin): client = OAuth2Session(client_id=int(settings.STRAVA_CLIENT_ID), client_secret=settings.SOCIAL_AUTH_STRAVA_KEY, scope="read") def create_authorization_url(self): return super().authorize( client=self.client, client_id=settings.STRAVA_CLIENT_ID, client_secret=settings.SOCIAL_AUTH_STRAVA_KEY, auth_url=settings.STRAVA_AUTH_URL, access_token_url=settings.STRAVA_ACCESS_TOKEN_URL, redirect_url=settings.STRAVA_REDIRECT_URL) def get_token(self, code): authorization_response = super().authorize( client=self.client, client_id=settings.STRAVA_CLIENT_ID, client_secret=settings.SOCIAL_AUTH_STRAVA_KEY, auth_url=settings.STRAVA_AUTH_URL, access_token_url=settings.STRAVA_ACCESS_TOKEN_URL, redirect_url=settings.STRAVA_REDIRECT_URL) response = super().get_token( self.client, settings.STRAVA_ACCESS_TOKEN_URL, authorization_response, code=code, client_id=settings.STRAVA_CLIENT_ID, client_secret=settings.SOCIAL_AUTH_STRAVA_KEY) return response
def authorized(): if "error" in request.args: # User cancelled the auth flow - discard auth (most likely there won't be any) session.pop("twitch_token", None) return redirect(url_for("mainpage")) twitch = OAuth2Session(config.CLIENT_ID, config.CLIENT_SECRET, state=session["login_state"]) resp = twitch.fetch_access_token("https://id.twitch.tv/oauth2/token", code=request.args["code"], # For some bizarre reason, we need to pass this information along. client_id=config.CLIENT_ID, client_secret=config.CLIENT_SECRET, redirect_uri=url_for("authorized", _external=True)) if "access_token" not in resp: # Something went wrong with the retrieval. No idea what or why, # so I'm doing a cop-out and just dumping to console. print("Unable to log in") pprint(resp) print("Returning generic failure.") raise Exception r = requests.get("https://api.twitch.tv/helix/users", headers={ "Client-ID": config.CLIENT_ID, "Authorization": "Bearer " + resp["access_token"], }) r.raise_for_status() user = r.json()["data"][0] database.ensure_user(user["id"], user["login"], user["display_name"]) session["twitch_user"] = user session["twitch_refresh_token"] = resp["refresh_token"] # Storing twitch_token is last. If you have this, you have everything. # (Kinda like the Gondoliers.) session["twitch_token"] = resp["access_token"] return redirect(url_for("mainpage"))
def get_access_token(self) -> str: """ Methods returns only access_token instance_url parameters are return by service, better to use it new method get_access_data return all information to connect (secret and instance_url) """ token = self.secrets_keeper.load(self.auth_flow_id) if 'expires_at' in token: expires_at = token['expires_at'] if isinstance(expires_at, bool): is_expired = expires_at elif isinstance(expires_at, (int, float)): is_expired = expires_at < time() else: is_expired = expires_at.timestamp() < time() if is_expired: if 'refresh_token' not in token: raise NoOAuth2RefreshToken client = OAuth2Session( client_id=self.config.client_id, client_secret=self.config.client_secret.get_secret_value(), ) new_token = client.refresh_token( self.token_url, refresh_token=token['refresh_token']) self.secrets_keeper.save(self.auth_flow_id, new_token) return self.secrets_keeper.load(self.auth_flow_id)['access_token']
def google_auth_redirect(): """ Step 3: Retrieving an access token. The user has been redirected back from the provider to your registered callback URL. With this redirection comes an authorization code included in the redirect URL. We will use that to obtain an access token. """ req_state = flask.request.args.get('state', default=None, type=None) print("Request Args: {}".format(json.dumps(flask.request.args))) if req_state != flask.session[AUTH_STATE_KEY]: response = flask.make_response('Invalid state parameter', 401) return response session = OAuth2Session(CLIENT_ID, CLIENT_SECRET, scope=AUTHORIZATION_SCOPE, state=flask.session[AUTH_STATE_KEY], redirect_uri=AUTH_REDIRECT_URI) oauth2_tokens = session.fetch_access_token( ACCESS_TOKEN_URI, authorization_response=flask.request.url) print(oauth2_tokens) # We use the session as a simple DB for this app. flask.session[AUTH_TOKEN_KEY] = oauth2_tokens # Uncomment to get insights into authentication process. #step3_logging(flask.request.url, oauth2_tokens) return flask.redirect(BASE_URI, code=302)
def google_auth_redirect(): req_state = flask.request.args.get("state", default=None, type=None) if req_state != flask.session[AUTH_STATE_KEY]: response = flask.make_response("Invalid state parameter", 401) return response session = OAuth2Session( CLIENT_ID, CLIENT_SECRET, scope=AUTHORIZATION_SCOPE, state=flask.session[AUTH_STATE_KEY], redirect_uri=request.base_url, ) oauth2_tokens = session.fetch_access_token( ACCESS_TOKEN_URI, authorization_response=flask.request.url ) flask.session[AUTH_TOKEN_KEY] = oauth2_tokens user_info = get_user_info() user = auth_services.load_user(id=user_info["email"]) if not user: auth_services.create_user( data={ "username": user_info["name"], "password": str(uuid.uuid4()), "email": user_info["email"], } ) user = auth_services.load_user(id=user_info["email"]) login_user(user, remember=True) return redirect(url_for("main.index"))
def get_access_data(self): """ Returns the access_token to use to access resources If necessary, this token will be refreshed """ access_data = self.secrets_keeper.load(self.auth_flow_id) logging.getLogger(__name__).debug('Refresh and get access data') if 'refresh_token' not in access_data: raise NoOAuth2RefreshToken if 'instance_url' not in access_data: raise NoInstanceUrl client = OAuth2Session( client_id=self.config.client_id, client_secret=self.config.client_secret.get_secret_value(), ) connection_data = client.refresh_token( self.token_url, refresh_token=access_data['refresh_token']) logging.getLogger(__name__).debug( f'Refresh and get access data new token {str(connection_data)}') self.secrets_keeper.save(self.auth_flow_id, connection_data) secrets = self.secrets_keeper.load(self.auth_flow_id) logging.getLogger(__name__).debug('Refresh and get data finished') return secrets
def send_sms_response(provider, notification_id, to): if provider == "sap": api_host_name = current_app.config["API_HOST_NAME"] from app.sap.oauth2 import OAuth2Client oauth2_client = OAuth2Client.query.first() session = OAuth2Session(oauth2_client.client_id, oauth2_client.client_secret) session.fetch_token(f'{api_host_name}/sap/oauth2/token') with session as client: headers = {"Content-type": "application/json"} body = sap_callback(notification_id, to) make_request(SMS_TYPE, provider, notification_id, body, headers, client=client) return elif provider == "telstra": headers = {"Content-type": "application/json"} body = telstra_callback(notification_id, to) elif provider == "twilio": headers = {"Content-type": "application/x-www-form-urlencoded"} body = twilio_callback(notification_id, to) else: raise ValueError("Invalid provider: {}".format(provider)) make_request(SMS_TYPE, provider, notification_id, body, headers)
def get_client(self, **kwargs): if "client" in kwargs.keys(): return kwargs.get("client") else: session = requests.Session() retries = Retry( total=3, status=3, connect=3, read=3, backoff_factor=0.5, method_whitelist=False, status_forcelist=[429, 504], ) session.mount("http://", HTTPAdapter(max_retries=retries)) session.mount("https://", HTTPAdapter(max_retries=retries)) oath_response = session.get( f"{self.client_config.oauth_host}/oauth/.well-known/openid-configuration" ).json() token_endpoint = oath_response["token_endpoint"] client = OAuth2Session( self.client_config.client_id, self.client_config.client_secret, scope="openid", token_endpoint=token_endpoint, grant_type="client_credentials", ) client.mount("http://", HTTPAdapter(max_retries=retries)) client.mount("https://", HTTPAdapter(max_retries=retries)) client.fetch_token() return client
def authorized(): if "error" in request.args: # User cancelled the auth flow - discard auth (most likely there won't be any) session.pop("twitch_token", None) return redirect(url_for("mainpage")) twitch = OAuth2Session(config.CLIENT_ID, config.CLIENT_SECRET, state=session["login_state"]) resp = twitch.fetch_access_token("https://id.twitch.tv/oauth2/token", code=request.args["code"], # For some bizarre reason, we need to pass this information along. client_id=config.CLIENT_ID, client_secret=config.CLIENT_SECRET, redirect_uri=os.environ.get("OVERRIDE_REDIRECT_URI") or url_for("authorized", _external=True)) if "access_token" not in resp: # Something went wrong with the retrieval. No idea what or why, # so I'm doing a cop-out and just dumping to console. print("Unable to log in", file=sys.stderr) pprint(resp, stream=sys.stderr) print("Returning generic failure.", file=sys.stderr) raise Exception session["twitch_token"] = resp["access_token"] session["twitch_refresh_token"] = resp["refresh_token"] session["twitch_auth_scopes"] = " ".join(sorted(resp["scope"])) # kraken_user = query("kraken/user", token="oauth") # The Kraken response includes fields not in Helix, including created_at, # and email (though Helix gives us the latter if we add an OAuth scope). user = query("helix/users", token="bearer")["data"][0] user["_id"] = user["id"] # For now, everything looks for _id. Existing logins don't have user["id"]. database.login_user(user["_id"], session["twitch_token"]) session["twitch_user"] = user return redirect(url_for("mainpage"))
def get_talent_info(token) -> TalentInfo: client = OAuth2Session(client_id, client_secret, token=token) # id, email, first_name, last_name resp = client.get('https://talent.kruzhok.org/api/users/me').json() return TalentInfo(id=resp['id'], email=resp['email'], first_name=resp['first_name'], last_name=resp['last_name'])
def test_token_expired(self): token = dict(access_token='a', token_type='bearer', expires_at=100) sess = OAuth2Session('foo', token=token) self.assertRaises( OAuthError, sess.get, 'https://i.b/token', )
def test_code_challenge(self): sess = OAuth2Session(client_id=self.client_id, code_challenge_method='S256') url = 'https://example.com/authorize' auth_url, _ = sess.create_authorization_url(url, code_verifier='hello') self.assertIn('code_challenge', auth_url) self.assertIn('code_challenge_method=S256', auth_url)