Google Authentication in a streamlit app

Hello !
I am Working on a simple streamlit app where i would like to add a Google Authentication before the user acess the app.
can anyone help me for doing that ?
Thank you all

2 Likes
  1. Create a new project on the Google Cloud Console:
  2. Enable the Google Sign-In API:
    • In the Google Cloud Console, navigate to the “APIs & Services” > “Library” section.
    • Search for “Google Sign-In API” and enable it for your project.
  3. Configure the OAuth consent screen:
    • In the Google Cloud Console, navigate to the “APIs & Services” > “OAuth consent screen” section.
    • Choose an “External” user type and click “Create”.
    • Provide a name for your application, enter the authorized domain (e.g., localhost for local development), and add any additional required information.
    • Save the changes.
  4. Create OAuth credentials:
    • In the Google Cloud Console, navigate to the “APIs & Services” > “Credentials” section.
    • Click “Create Credentials” and select “OAuth client ID”.
    • Choose “Web application” as the application type.
    • Enter a name for the OAuth client ID.
    • Add the authorized JavaScript origins (e.g., http://localhost:8501 for Streamlit’s default development server).
    • Add the authorized redirect URI (e.g., http://localhost:8501/).
    • Click “Create” to generate the OAuth client ID and client secret.
  5. Install the required Python libraries:
    • Open a terminal or command prompt and install the google-auth library using pip:
     pip install google-auth
  1. Implement the Google Authentication in your Streamlit app:
    • Import the necessary libraries in your Python script:
     import streamlit as st
     from google.oauth2 import id_token
     from google.auth.transport import requests
  1. Add the authentication logic in your Streamlit app:
def main():
    st.title("Your Streamlit App")
    
    # Google Authentication
    st.subheader("Google Authentication")
    client_id = "YOUR_CLIENT_ID"  # Replace with your OAuth client ID
    token = st.text_input("Enter your Google ID token", type="password")
    if st.button("Authenticate"):
        try:
            idinfo = id_token.verify_oauth2_token(token, requests.Request(), client_id)
            if idinfo['aud'] != client_id:
                raise ValueError("Invalid client ID")
            st.success(f"Authentication successful: {idinfo['name']}")
            # Continue with the rest of your app logic here
        except ValueError as e:
            st.error("Authentication failed")
            st.error(e)
    
    # Other app content
    # ...
    
if __name__ == "__main__":
    main()
  • Replace "YOUR_CLIENT_ID" with your OAuth client ID obtained from the Google Cloud Console.
  1. Run your Streamlit app:
    • Open a terminal or command prompt and navigate to the directory where your Python script is located.
    • Run your Streamlit app using the following command:
streamlit run your_script.py
8 Likes

Hello @AdryanSerage, thank you for the reply !
While looking for “Google Sign-In API”, I found that it’s deprecated (I think) here is where i’ve read that Link .

Is that correct ? and is it “Cloud Identity API” now ?
If Yes, is there more steps or modifications that i have to do ?

1 Like

Use that instead : Overview  |  Authentication  |  Google Developers

2 Likes

Ok !
So as I understood, now , there is no API service to enable ?

1 Like

You could use this : Authorizing for Web  |  Authorization  |  Google Developers

and read that : Python quickstart  |  People API  |  Google Developers

1 Like

Hello,
I don’t know if you can help me more, but here what i’ve done until now :

  1. I followed these steps. At the end i got a json file with (“client_id”, “project_id”,“auth_uri”,“token_uri”, “auth_provider_x509_cert_url”, “client_secret”, “redirect_uris”).
  2. I Enabled " People API" and followed these instructions, so created “quickstart.py.py” where i referred (in this line flow = InstalledAppFlow.from_client_secrets_file('secret.json', SCOPES) to the json file a got earlier.

When i run this script, a webpage with “google prompts authorize access” opened, with this error : “Erreur 400 : redirect_uri_mismatch”.

I need to implement this into a streamlit app, but I still have some logic issues to understand correctly the process.

1 Like

You have the right logic, just you have to check the redirect_uri_mismatch that’s mean that you didn’t input the right redirect URL in google auth.

1 Like

@AdryanSerage Can you please explain, where do I get Google ID token?
I’ve completed all steps, and tried to get the token from: OAuth 2.0 Playground but app keeps throwing an error: Wrong number of segments in token

What I’m missing?

1 Like

I am a bit confused, in the “authorized redirect URI” section (on my Google cloud account), I have written :

That’s because I am running it locally, but I still have the same error.
I also don’t know how to implement it into a streamlit app. Maybe only copy and paste this code part and put it beginning of the main.py file ?

1 Like

Hello guys I’m trying to do the same thing!
So good to find this thread.

I have one question though. I’m trying to use Firebase. How can I add a Google login (the same as here using “login with Google”) in a way that creates a user in the Firebase’s user base?

Thanks in advance!
Best.

1 Like

To obtain a Google ID token, you need to follow the correct steps. The error message you mentioned, “Wrong number of segments in token,” typically indicates an issue with the token format. Here’s a step-by-step guide to obtaining a Google ID token:

  1. Go to the Google API Console.
  2. Create a new project or select an existing project from the dropdown menu at the top.
  3. Enable the necessary APIs for your project. For obtaining an ID token, you’ll likely need to enable the “Google Sign-In API” or any other relevant APIs based on your requirements.
  4. Once the APIs are enabled, click on the “Credentials” tab in the left menu.
  5. On the Credentials page, click the “Create credentials” button and select “OAuth client ID.”
  6. Choose the application type that suits your needs. If you’re running the OAuth flow on a web server, select “Web application.” Fill in the necessary details such as the authorized JavaScript origins and redirect URIs. Ensure that the redirect URI is correctly specified and matches the location where your application will receive the token.
  7. After creating the OAuth client ID, you should see it listed on the Credentials page. Under the “OAuth 2.0 client IDs” section, locate the client ID you just created.
  8. Copy the client ID and paste it into the OAuth 2.0 Playground (OAuth 2.0 Playground).
  9. In the OAuth 2.0 Playground, click on the “OAuth 2.0 Configuration” button on the right side. Paste your client ID in the “OAuth Client ID” field.
  10. Scroll down to the “Step 1: Select & authorize APIs” section in the Playground. Choose the desired scopes and click the “Authorize APIs” button.
  11. Follow the prompts to sign in with your Google account and grant the necessary permissions.
  12. After authorization, the Playground will display various API endpoints. You can select the relevant endpoint you want to test.
  13. Finally, click on the “Exchange authorization code for tokens” button. This should generate an access token and a refresh token. The access token is what you typically use for authentication purposes.
1 Like

If you’re running your application locally on http://localhost:8501/ or http://localhost/, the redirect URIs you provided should be correct. However, there are a few additional steps you need to follow in order to integrate the Google ID token retrieval into your Streamlit app.

Here’s a step-by-step guide on how to implement Google ID token retrieval in a Streamlit app:

  1. Make sure you have the necessary dependencies installed. You can use the google-auth library to handle the authentication process. Install it using the following command:

shellCopy code

pip install google-auth
  1. In your Streamlit app’s Python file (main.py), import the required libraries:

pythonCopy code

import streamlit as st
from google.oauth2 import id_token
from google.auth.transport import requests
  1. Create a function to handle the token retrieval. This function will take the authorization code and client ID as input and return the ID token:

pythonCopy code

def get_google_id_token(auth_code, client_id):
    try:
        token = id_token.fetch_id_token(requests.Request(), auth_code, client_id)
        return token
    except ValueError as e:
        st.error(f"Error retrieving ID token: {e}")
  1. In your Streamlit app’s main code, add a button or a link for users to initiate the authentication process. When the user clicks the button or link, they will be redirected to the Google Sign-In page:

pythonCopy code

# Your Streamlit app code
st.write("Welcome to My App!")

if st.button("Sign in with Google"):
    # Redirect the user to the Google Sign-In page
    auth_url = "https://accounts.google.com/o/oauth2/auth"
    client_id = "YOUR_CLIENT_ID"  # Replace with your actual client ID
    redirect_uri = "http://localhost:8501/"  # Replace with your redirect URI
    scope = "openid"  # Replace with the desired scopes
    state = "state123"  # Replace with a unique state value
    auth_endpoint = f"{auth_url}?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={scope}&state={state}"
    st.markdown(f'<a href="{auth_endpoint}">Click here to sign in with Google</a>', unsafe_allow_html=True)
  1. Once the user completes the Google Sign-In flow and is redirected back to your app’s redirect URI (http://localhost:8501/), you need to handle the callback. You can add the following code snippet to the top of your main.py file to handle the callback route:

pythonCopy code

import streamlit.ReportThread as ReportThread
from streamlit.server.Server import Server

# Handle OAuth2 callback route
AUTHORIZATION_CODE = "code"
REDIRECT_URI = "http://localhost:8501/"  # Replace with your redirect URI

if st._is_running_with_streamlit:
    ctx = ReportThread.get_report_ctx()
    session_id = ctx.session_id
    session_info = Server.get_current()._session_info_by_id[session_id]

    if session_info.ws.request_info.request_line == "GET /":
        auth_code = session_info.ws.request_info.query_params[AUTHORIZATION_CODE]
        get_google_id_token(auth_code, "YOUR_CLIENT_ID")  # Replace with your actual client ID
        # Continue with the rest of your app's logic

Make sure to replace "YOUR_CLIENT_ID" with your actual client ID obtained from the Google API Console.

2 Likes

To add Google login functionality to your Firebase project and create a user in Firebase’s user base, you can follow these steps:

  1. Set up Firebase:
  • Go to the Firebase Console and create a new project or select an existing project.
  • Set up your project by following the instructions provided in the Firebase Console.
  1. Enable Google Sign-In in Firebase:
  • In the Firebase Console, go to the “Authentication” section.
  • Select the “Sign-in method” tab.
  • Enable the “Google” sign-in provider and click on it to configure it.
  • Follow the instructions to provide the necessary information, such as the web client ID (which you can obtain from the Google API Console) and any additional settings you require.
  1. Add the necessary Firebase and Google client libraries:
  • In your project’s HTML file (or template), include the Firebase SDK and the Google Sign-In client library.
  • For the Firebase SDK, add the following script tag:

htmlCopy code

<script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-auth.js"></script>
  • For the Google Sign-In client library, add the following script tag:

htmlCopy code

<script src="https://accounts.google.com/gsi/client" async defer></script>
  1. Initialize Firebase and Google Sign-In:
  • In your JavaScript code, initialize Firebase with your project’s Firebase configuration. You can obtain the configuration object from the Firebase Console.
  • Initialize the Google Sign-In client with your Google client ID:

javascriptCopy code

const auth = firebase.auth();

// Initialize Google Sign-In
const googleProvider = new firebase.auth.GoogleAuthProvider();
googleProvider.setCustomParameters({ prompt: 'select_account' });

// Configure sign-in with Google button
const googleSignInButton = document.getElementById('google-sign-in-button');
googleSignInButton.addEventListener('click', () => {
  auth.signInWithPopup(googleProvider)
    .then((result) => {
      // Handle successful sign-in
      const user = result.user;
      // User is now signed in with Firebase and you can access the user object
    })
    .catch((error) => {
      // Handle error
      console.error(error);
    });
});
  1. Add the Google Sign-In button to your HTML:
  • In your HTML file, add a button or any desired element that will trigger the Google Sign-In flow.
  • Assign it an ID, such as “google-sign-in-button”:

htmlCopy code

<button id="google-sign-in-button">Sign in with Google</button>
  1. Handle user creation in Firebase:
  • After a successful sign-in, the result.user object will contain the user information, including the user’s unique identifier (uid).
  • You can use this information to create or update a user in Firebase’s user base, if needed.

With these steps, you can integrate Google Sign-In with Firebase and create a user in Firebase’s user base when a user signs in with Google.

1 Like

Hello!
I’m working on Google Oauth authentication for a streamlit app, but the problem arises that both external and internal accounts are allowing login from any Google account and not just the emails listed as a test user. This issue is also discussed here Google Issue Tracker
Has anyone here ever gone through this?

1 Like

hello @AdryanSerage, thank you for this step by step code.
I want to ask about the last step (to handle the callback route) :
I think that these imports are no longuer available in streamlit :

  • import streamlit.ReportThread as ReportThread
  • from streamlit.server.Server import Server
    is there a n other way to handle the callback ?

Thank you !

3 Likes

Hey guys, I don’t know if your already solve this problem but. I would like to give my contribution:

based on the preview comments and on this guide (Using OAuth 2.0 for Web Server Applications):

I created this simple code that works fine for me:

import os

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


redirect_uri = os.environ.get("REDIRECT_URI", "http://localhost:8501/")


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", # 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
    else:
        if st.button("Sign in with Google"):
            authorization_url, state = flow.authorization_url(
                access_type="offline",
                include_granted_scopes="true",
            )
            webbrowser.open_new_tab(authorization_url)


def main():
    if "google_auth_code" not in st.session_state:
        auth_flow()

    if "google_auth_code" in st.session_state:
        email = st.session_state["user_info"].get("email")
        st.write(f"Hello {email}")


if __name__ == "__main__":
    main()

4 Likes

Thanks for your solution! I tried implementing it, and it works!
but I have a concern; after I set the login, I want my usual flow or app to display.
I have a chart and a table to display in my app, but the whole view got shrunk from container width to reduced width.
Are there any best practices to follow to have your app flow work as usual after the authentication?

1 Like

Hey,

I would create a function with the rest of your flow, and replace here:

if "google_auth_code" in st.session_state:
        main_flow()
2 Likes

Thanks! I did exactly this, but even though I was using container_width = True in my table and chart, the view changed to a reduced view towards the center of my screen.
I will check if the login buttons or the display logged in information changed that or not.

1 Like