Managing states and pages

In the code example below, main() runs first and as part of it runs auth_flow() also. So the first page shown is (correctly) the Sign In With Google page.

At the end of auth_flow(), I have included a call to function main_content() so that this function runs straight after. If I remove this, then main_content() doesn’t run.

After I sign in with Google on the page and give permission, streamlit navigates to the Log In page (this is separate to the Sign In With Google Page), which is what I want BUT the issue is that the Sign In With Google button and the st.write(“Welcome to Actio AI!”) are still showing. These should not be showing after auth_flow() has finished executing and main_content() is called.

This is what it looks like after I sign in with Google and give permission then streamlit redirects to the separaqte Log In Page. As you can see, both the Sign In with Google button and the welcome message are still showing on this page whereas these two shouldn’t be.

BTW: Main_content() below is a longer block of code. I have just reduced it in the example below for simplicity.

import google_auth_oauthlib.flow
import webbrowser
from googleapiclient.discovery import build
import streamlit as st

def auth_flow():
    st.session_state.page = "Google Sign-In"
    
    st.write("Welcome to Actio AI!")

    flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
        "client_secret.json", # replace with your JSON credentials from your Google Auth app
        scopes=["https://www.googleapis.com/auth/userinfo.email", "openid"],
        redirect_uri=redirect_uri,
    )

    if st.button("Sign in with Google"):
        authorization_url, state = flow.authorization_url(
            access_type="offline",
            include_granted_scopes="true",
            prompt="consent"
        )
        webbrowser.open_new_tab(authorization_url)
    
    auth_code = st.experimental_get_query_params().get("code")

    if auth_code:
        auth_code = auth_code[0]
        flow.fetch_token(code=auth_code)
        credentials = flow.credentials
        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
        main_content()

def main():
    st.set_page_config(layout="wide")
    
    if "google_auth_code" not in st.session_state or not st.session_state.google_auth_code:
        auth_flow()
    else:
        main_content()

def main_content():
    if "data" not in st.session_state:
        st.session_state.data = {
            "person_locations": [],
            "organization_num_employees_ranges": [],
            "person_titles": [],
            "q_organization_keyword_tags": [],
            "apollo_find_data": []
        }

That code triggers a code rerun from top to bottom. So you will see it again.

Better is to use the on_click parameter of the button to run a function and get/set all you need there. Something like:

def process_auth():
    # other stuff
    st.session_state["google_auth_code"] = auth_code
    # other stuff

st.button("Sign in with Google", on_click=process_auth)

The advantage of this setup is that st.session_state["google_auth_code"] has been defined already in the process_auth() right after the button is clicked, and any code reruns will no longer enter the block.

if "google_auth_code" not in st.session_state or not \
    st.session_state.google_auth_code:

References

Thanks for your reply.

I am a bit confused. I have changed:

 if st.button("Sign in with Google"):
        authorization_url, state = flow.authorization_url(
            access_type="offline",
            include_granted_scopes="true",
            prompt="consent"
        )
        webbrowser.open_new_tab(authorization_url)

to:

    def process_auth():
            authorization_url, state = flow.authorization_url(
                access_type="offline",
                include_granted_scopes="true",
                prompt="consent"
            )
            st.session_state["google_auth_code"] = auth_code
            webbrowser.open_new_tab(authorization_url)
    
    st.button("Sign in With Google",on_click=process_auth)

process_auth() is inside auth_flow() (just as “if st_button” was) and I haven’t changed anything else. However, I face the same issue as before. What am I doing wrong?

Based from your current posted code above, you have not defined the auth_code.

Somehow you have to capture it from:

auth_code = st.experimental_get_query_params().get("code")

Although experimental_get_query_params is already deprecated.