--- title: Boardgames Tracker emoji: 🚀 colorFrom: red colorTo: red sdk: docker app_port: 8501 tags: - streamlit pinned: false short_description: Streamlit template space license: mit --- # Welcome to Streamlit! Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart: If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community forums](https://discuss.streamlit.io). ## Persistence setup (Google login + Sheets) The app works fully anonymously with no setup. Logging in with Google (button in the sidebar) additionally persists your players and round history to a Google Sheet -- created directly in **your own Drive**, owned by you. There's no service account and no shared storage involved: Drive access uses the `drive.file` scope, so the app can only create/edit the one spreadsheet it creates for you (`BoardGameTracker - {your email}`), nothing else in your Drive. Because it's created by your own account, it uses your own storage -- there's no "service account has 0 storage quota" issue to work around. Trade-off: since the app stays in Google's "Testing" publishing status (no Google security review needed for a small friend group), each person who connects Drive must first be added as a **test user** in the OAuth consent screen, and will see an "unverified app" warning the first time they click through. **Login vs. Drive access are two separate steps.** `st.login()` (sidebar button) only ever handles identity -- it deliberately never exposes a `refresh_token` to app code, no matter what scope you ask for. So once logged in, a separate one-time **Connect Google Drive** button appears in the sidebar; clicking it runs its own OAuth exchange (`access_type=offline` + `prompt=consent`) to force Google to hand back a `refresh_token`, which gets encrypted and stored in a long-lived browser cookie (via `extra-streamlit-components`' `CookieManager`, since Streamlit page code has no direct access to set real HttpOnly cookies). From then on, on that same browser, the app silently mints a fresh access token from the stored refresh_token -- no repeat consent screen -- until it's revoked (e.g. you remove the app's access in your Google account) or the browser's cookies are cleared. This is per-browser/device, not per-account centrally: a new device or browser needs to click Connect Drive once, same as the very first time. The cookie only ever holds the encrypted blob; the decryption key lives purely in server-side secrets and never reaches the browser. ### One-time Google Cloud setup 1. Create an OAuth 2.0 **Web application** Client ID; add your app's URL(s) **with the `/oauth2callback` path** as authorized redirect URIs (e.g. `http://localhost:8501/oauth2callback` for local dev, and `https://.hf.space/oauth2callback` for a deployed Space). Streamlit only processes the OAuth code exchange at that exact path -- a bare app URL without `/oauth2callback` will silently fail to complete login (no error, but `st.user.is_logged_in` never becomes `True`). 2. On the OAuth consent screen, add every player's Google account email under **Test users** (keep publishing status as "Testing" -- this avoids Google's verification review entirely for `drive.file`, a scope that only grants access to files the app itself creates). 3. No service account, no Sheets/Drive API project-level enablement, no index spreadsheet -- the app's own OAuth client handles everything. ### Local dev — `.streamlit/secrets.toml` (gitignored, never commit this) ```toml [auth] redirect_uri = "http://localhost:8501/oauth2callback" cookie_secret = "" client_id = "" client_secret = "" server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration" [cookies] encryption_key = "" ``` ### Hugging Face Space deploy `st.login()` only reads `st.secrets`, so `src/bootstrap_secrets.py` assembles `.streamlit/secrets.toml` at startup from individual Space secrets (Settings → Variables and secrets), so nothing sensitive needs to live in the repo or the image: `AUTH_CLIENT_ID`, `AUTH_CLIENT_SECRET`, `AUTH_COOKIE_SECRET`, `AUTH_REDIRECT_URI` (your Space's public URL **with `/oauth2callback` appended**, e.g. `https://randomcatlover-boardgames-tracker.hf.space/oauth2callback`), `COOKIE_ENCRYPTION_KEY`.