From 2c250f601b177bb9c82f7324baa3787a675d0097 Mon Sep 17 00:00:00 2001 From: Moritz Graf Date: Tue, 6 Jan 2026 13:39:43 +0100 Subject: [PATCH] docs: clarify oauth vs api key and add setup steps --- README.md | 33 +++++++++++++++++---------- scripts/manage_secrets.py | 6 +++++ technical_details_auth.md | 48 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 technical_details_auth.md diff --git a/README.md b/README.md index 7cef2fd..a3c3b52 100644 --- a/README.md +++ b/README.md @@ -29,18 +29,27 @@ We use Terraform to manage Firebase Authentication and Firestore. To set this up ### 1. Manual Prerequisites (One-time) 1. **Create a Project**: Go to [Google Cloud Console](https://console.cloud.google.com/) and create a new project. 2. **Enable Billing**: Link a Billing Account to this project (Required for Terraform to enable Identity Platform). -3. **Local Auth**: - ```bash - gcloud auth login - gcloud auth application-default login - ``` -4. **Configure Secrets**: - Run the helper script to create and populate the required secrets in Google Secret Manager: - ```bash - ./scripts/manage_secrets.py - ``` - *(You will need the Client ID and Secret from the GCP Console > APIs & Services > Credentials)* -5. **Verify**: Log in to the application. You should see the member banner. + 3. **Local Auth**: + ```bash + gcloud auth login + gcloud auth application-default login + ``` + 4. **Configure OAuth (Crucial Step)**: + * Go to [APIs & Services > OAuth consent screen](https://console.cloud.google.com/apis/credentials/consent). + * Select **External** -> Create. + * Fill in: App Name ("Haumdaucher"), Support Email, and Developer Contact Email. Click **Save and Continue** (You can skip scopes/test users for now). + * Go to [Credentials](https://console.cloud.google.com/apis/credentials). + * Click **+ Create Credentials** > **OAuth client ID**. + * Type: **Web application**. + * Name: "Haumdaucher Web". + * **Important**: Add `http://localhost:5173` to **Authorized JavaScript origins**. + * Click **Create**. + 5. **Configure Secrets**: + Run the helper script and paste the **Client ID** and **Client Secret** you just created: + ```bash + ./scripts/manage_secrets.py + ``` + 6. **Verify**: Log in to the application. You should see the member banner. ## 🛠 Local Development Requirements diff --git a/scripts/manage_secrets.py b/scripts/manage_secrets.py index 8f1b6bb..d8ba63c 100755 --- a/scripts/manage_secrets.py +++ b/scripts/manage_secrets.py @@ -109,6 +109,12 @@ def main(): create_secret(secret_id) # Prompt for value + if secret_id == "haumdaucher-oauth-client-id": + print(f" â„šī¸ Go to GCP Console > Credentials > OAuth 2.0 Client IDs") + print(f" Copy the 'Client ID' (ends in .apps.googleusercontent.com)") + elif secret_id == "haumdaucher-oauth-client-secret": + print(f" â„šī¸ Copy the 'Client Secret' (shorter string, hidden in console)") + print(f" Enter value for {description} (Input hidden): ") # Use getpass logic via manual read to support all shells or just input() but masked? # getpass in python is better. diff --git a/technical_details_auth.md b/technical_details_auth.md new file mode 100644 index 0000000..0ef7958 --- /dev/null +++ b/technical_details_auth.md @@ -0,0 +1,48 @@ +# Technical Details: Authentication & Infrastructure + +This document explains the "Hybrid" approach we use for managing Authentication infrastructure on Google Cloud Platform (GCP). + +## 🏗 The Architecture + +We use **Terraform** to manage our "Infrastructure as Code". This gives us reproducibility and version control. However, Authentication involves sensitive credentials that have security restrictions preventing full automation. + +### Components +1. **Firebase Auth (Identity Platform)**: Handles user login (Google Sign-In). +2. **Firestore**: database storing the "Allowlist" of approved emails. +3. **Secret Manager**: securely stores the OAuth credentials used by Identity Platform. + +## 🔐 The "Client Secret" Dilemma + +### 1. Why is there a Manual Step? +When you enable Firebase Authentication, Google creates an **OAuth 2.0 Client ID** for your web application. This Client ID comes with a **Client Secret**. + +**The Restriction**: Google Cloud's security model **does not allow** retrieving an existing Client Secret via the API or CLI (`gcloud`). It is only visible: +1. At the moment of creation. +2. In the GCP Console UI (where you can "download JSON"). + +Because Terraform interacts via the API, it **cannot** fetch this secret on its own. If we tried to create a *new* Client ID via Terraform, we would hit another blocker: the **OAuth Consent Screen** requires manual configuration in the Console. + +### 2. The Solution: "Bootstrap" Script +To bridge this gap, we use a "Bootstrap" workflow: + +1. **Creation**: Firebase auto-creates the credentials. +2. **Retrieval**: You manually copy them from the Console (the only place they are visible). +3. **Storage**: You run `scripts/manage_secrets.py` to save them into **Google Secret Manager**. +4. **Consumption**: Terraform reads the secure values from Secret Manager to configure the Identity Provider. + +## 🔄 Authentication Flow + +1. **User Visits Site**: The Vue.js app initializes Firebase using public config (API Key, Auth Domain). +2. **Login**: User clicks "Login". The app invokes `signInWithPopup(googleProvider)`. + * Google checks the allow-listed domains (`localhost`, `*.firebaseapp.com`). + * The "Client ID" is used to identify the app to Google. +3. **Token Exchange**: Identity Platform validates the user's Google credentials using the **Client Secret** (configured via Terraform). +4. **Success**: If valid, the user is signed in. +5. **Authorization**: The app watches `config/allowlist` in Firestore. + * If `user.email` is in the list -> **Banner: "Do bist a haumdaucher"**. + * If not -> Access is restricted. + +## 📝 Terraform Resources involved +* `google_identity_platform_default_supported_idp_config`: Configures the "Google" provider. +* `data "google_secret_manager_secret_version"`: Fetches the stored credentials. +* `google_firestore_document`: Manages the allowlist.