Addplace / youtube_auth.py
Kosala Nayanajith Deshapriya
Fix Google OAuth iframe 403 block
fcce9fe
Raw
History Blame Contribute Delete
2.98 kB
"""
youtube_auth.py β€” OAuth2 using root redirect URI (no PKCE)
"""
import os
import json
import streamlit as st
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import Flow
from google.auth.transport.requests import Request
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
SCOPES = [
"https://www.googleapis.com/auth/youtube.readonly",
"https://www.googleapis.com/auth/yt-analytics.readonly",
]
def get_client_config():
env_secret = os.getenv("GOOGLE_CLIENT_SECRETS")
if env_secret:
return json.loads(env_secret)
if os.path.exists("client_secret.json"):
with open("client_secret.json") as f:
return json.load(f)
raise FileNotFoundError("No Google credentials found.")
def get_redirect_uri():
space_host = os.getenv("SPACE_HOST")
if space_host:
return f"https://{space_host}/"
render_url = os.getenv("RENDER_EXTERNAL_URL")
if render_url:
return f"{render_url}/"
return "http://localhost:8501/"
def build_flow():
config = get_client_config()
flow = Flow.from_client_config(
config,
scopes=SCOPES,
redirect_uri=get_redirect_uri()
)
# Explicitly disable PKCE β€” google-auth-oauthlib 1.4.0 auto-enables it,
# but Streamlit loses session state during the Google redirect so the
# code_verifier cannot be persisted.
flow.autogenerate_code_verifier = False
flow.code_verifier = None
return flow
def get_credentials():
params = dict(st.query_params)
# ── Handle OAuth callback ──
if "code" in params:
try:
flow = build_flow()
flow.fetch_token(
code=params["code"],
include_client_id=True
)
creds = flow.credentials
st.session_state["google_creds"] = creds.to_json()
st.query_params.clear()
return creds
except Exception as e:
st.error(f"Login failed: {e}. Please try again.")
st.query_params.clear()
return None
# ── Restore from session_state ──
if "google_creds" in st.session_state:
try:
creds = Credentials.from_authorized_user_info(
json.loads(st.session_state["google_creds"]), SCOPES
)
if creds.valid:
return creds
if creds.expired and creds.refresh_token:
creds.refresh(Request())
st.session_state["google_creds"] = creds.to_json()
return creds
except Exception:
del st.session_state["google_creds"]
return None
def show_login_button():
flow = build_flow()
auth_url, _ = flow.authorization_url(
prompt="consent",
access_type="offline",
include_granted_scopes="true"
)
return auth_url
def logout():
if "google_creds" in st.session_state:
del st.session_state["google_creds"]