Google Authentication with Streamlit user_email not being found

Hello. I am trying to make a simple app where the user can click a button to sign in with google authentication. Everything works, but the third print function in get_logged_in_user_email() never runs because the line before doesn’t get the right info. Please help! Thanks!

import asyncio
import httpx
import streamlit as st
import firebase_admin
from firebase_admin import credentials, auth, initialize_app, exceptions
from httpx_oauth.clients.google import GoogleOAuth2

# Initialize Firebase Admin SDK
cred = credentials.Certificate("firestore-key.json")
try:
    firebase_admin.get_app()
except ValueError as e:
    initialize_app(cred)

redirect_url = "http://localhost:8501/"
client = GoogleOAuth2(client_id=st.secrets["client_id"], client_secret=st.secrets["client_secret"])

if "email" not in st.session_state:
    st.session_state.email = ''

async def get_access_token(client: GoogleOAuth2, redirect_url: str, code: str):
    return await client.get_access_token(code, redirect_url)

async def get_email(client:GoogleOAuth2, token: str):
    user_id, user_email = await client.get_id_email(token)
    return user_id, user_email

def get_logged_in_user_email():
    try:
        code = st.query_params["code"]

        if code:
            print("#1")
            token = asyncio.run(get_access_token(client=client, redirect_url=redirect_url, code=code))
            st.query_params.clear()

            if token:
                print("#2")
                user_id, user_email = asyncio.run(get_email(client, token["access_token"])) ## The problem is here. user_email is empty
                if user_email:
                    print("#3")
                    try:
                        user = auth.get_user_by_email(user_email)
                    except exceptions.FirebaseError:
                        user = auth.create_user(email=user_email)
                    st.session_state.email = user.email
                    return user.email
        return None
    except:
        pass


def show_login_button():
    authorization_url = asyncio.run(client.get_authorization_url(redirect_url, scope=["email", "profile"], extras_params={"access_type": "offline"}))
    st.markdown(f"<a href='{authorization_url}' target='_self'>Login</a>", unsafe_allow_html=True)
    get_logged_in_user_email()


def app():
    st.title("Welcome")
    if not st.session_state.email:
        get_logged_in_user_email()
        show_login_button()

    st.session_state

    if st.session_state.email:
        st.write(st.session_state.email)
        if st.button("logout", type="primary", key="logout_button"):
            st.session_state.email = ''
            st.rerun()

if __name__ == "__main__":
    app()```

Firebase has an OIDC option. Do you need authorization, or is authentication sufficient for your case? Streamlit 1.42.0 just released native support for user authentication for OIDC providers.

1 Like