I am facing a similar issue. I am using the YouTube Data API to gather channel and video data. I have my app deployed to Streamlit but any request that requires oauth instead of an api key gives me the error below. I can run both types of requests all day in a local Streamlit server. The function to authenticate that works locally is below too.
Traceback (most recent call last):
File "/home/adminuser/venv/lib/python3.9/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 535, in _run_script
exec(code, module.__dict__)
File "/mount/src/concord/app_scripts/app.py", line 67, in <module>
create_playlists_from_data()
File "/mount/src/concord/app_scripts/app_create_playlist_add_videos_from_existing_playlist_data.py", line 161, in create_playlists_from_data
youtube = authenticate_youtube_api()
File "/mount/src/concord/app_scripts/app_create_playlist_add_videos_from_existing_playlist_data.py", line 43, in authenticate_youtube_api
credentials = flow.run_local_server(port=9000)
File "/home/adminuser/venv/lib/python3.9/site-packages/google_auth_oauthlib/flow.py", line 444, in run_local_server
webbrowser.get(browser).open(auth_url, new=1, autoraise=True)
File "/usr/local/lib/python3.9/webbrowser.py", line 65, in get
raise Error("could not locate runnable browser")
webbrowser.Error: could not locate runnable browser
While this does work locally, it fails when posted to the Streamlit Cloud. The webbrowser does not exist - on purpose according to Streamlit Cloud people - and thus it will never open a new tab. I have now tried this approach, flow-run_local_server, and even a URL link. Nothing works when hosted.
Has anybody posted their project to the Streamlit Cloud with OAuth and had it work?
Hi @Ken_Tola, although I haven’t tested on Streamli Cloud yet I managed to get it working without webbrowser. Saw the limitation of webbrowser here. My work around was creating a link button. See my full code below for your reference.
from streamlit_js import st_js, st_js_blocking
def ls_get(k, key=None):
return st_js_blocking(f"return JSON.parse(localStorage.getItem('{k}'));", key)
def ls_set(k, v, key=None):
jdata = json.dumps(v, ensure_ascii=False)
st_js_blocking(f"localStorage.setItem('{k}', JSON.stringify({jdata}));", key)
def init_session():
user_info = ls_get("user_info")
if user_info:
st.session_state["user_info"] = user_info
def auth_flow():
st.write("Welcome to My App!")
auth_code = st.query_params.get("code")
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
client_secret_json_path, # replace with you json credentials from your google auth app
scopes=["https://www.googleapis.com/auth/userinfo.email", "openid"],
redirect_uri=redirect_uri,
)
if auth_code:
flow.fetch_token(code=auth_code)
credentials = flow.credentials
st.write("Login Done")
user_info_service = build(
serviceName="oauth2",
version="v2",
credentials=credentials,
)
user_info = user_info_service.userinfo().get().execute()
assert user_info.get("email"), "Email not found in infos"
st.session_state["google_auth_code"] = auth_code
st.session_state["user_info"] = user_info
ls_set("user_info", user_info)
# TODO fix calling consecutive ls_set is not working
# ls_set("google_auth_code", auth_code)
else:
authorization_url, state = flow.authorization_url(
access_type="offline",
include_granted_scopes="true",
)
st.link_button("Sign in with Google", authorization_url)
def main():
init_session()
if "user_info" not in st.session_state:
auth_flow()
if "user_info" in st.session_state:
main_flow()
if __name__ == "__main__":
main()
Thank you so much for your code – I really appreciate it!
When I run your code, I get back every scope that I have ever accessed in Google with my ID – including many that I have long since disabled. This change in scope crashes the site, do you have any suggestions for how to prevent this from occurring?
Hi @Ken_Tola, I am not familiar with the error. Depending on the stage of development you are at, you can create a new OAuth 2.0 Client with the scope that you want. Sorry, can’t be of much help on this.
Worked for me!
For anyone who’s interested to make the button look official, here is the link to customize a streamlit button, and the css can be found here
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.