390 lines
21 KiB
Markdown
390 lines
21 KiB
Markdown
# Google OAuth Verification — Boilerplates für Porta
|
||
|
||
> Begleitdokument zu `google-oauth-setup.md`. Enthält copy-paste-fähige
|
||
> Bausteine für die Google Trust-&-Safety-Verifizierung der **Porta**-App
|
||
> (`porta.poweron.swiss`, Developer: `p.motsch@poweron.swiss`,
|
||
> GCP-Projekt `<GCP-Neu-Generieren>`).
|
||
|
||
## App-Daten (zur konsistenten Wiederverwendung)
|
||
|
||
| Feld | Wert |
|
||
|----------------------------|-----------------------------------------------------------------------------------------------|
|
||
| App-Name | Porta |
|
||
| Anbieter (Legal Entity) | PowerOn AG |
|
||
| Verifizierte Domain | `poweron.swiss` |
|
||
| Homepage-URL | `https://porta.poweron.swiss/poweron-home.html` |
|
||
| Privacy-Policy-URL | `https://porta.poweron.swiss/poweron-privacy.html` |
|
||
| Terms-of-Service-URL | `https://porta.poweron.swiss/poweron-terms.html` |
|
||
| Support-E-Mail | `support@poweron.swiss` |
|
||
| Developer-Kontakt | `p.motsch@poweron.swiss` |
|
||
| GCP-Projekt-Nummer | `<GCP-Neu-Generieren>` |
|
||
| GCP-Projekt-ID | (siehe `env_prod.env`, `Service_GOOGLE_DATA_CLIENT_ID`) |
|
||
| Verwendete Google-Scopes | `openid`, `userinfo.email`, `userinfo.profile`, `gmail.readonly`, `drive.readonly` |
|
||
|
||
> Bei jeder Änderung an Scopes (`platform-core/modules/auth/oauthProviderConfig.py::googleDataScopes`)
|
||
> diese Tabelle, die OAuth-Consent-Screen-Konfiguration in der GCP-Console
|
||
> **und** die Privacy-Policy synchron halten — Google bouncet sonst die
|
||
> Verification.
|
||
|
||
---
|
||
|
||
## 1. Privacy-Policy-Sektion zu Google-Daten
|
||
|
||
Die folgenden zwei Sektionen müssen **wortgleich** auf `https://porta.poweron.swiss/poweron-privacy.html`
|
||
unter denselben Domain-/HTTPS-Bedingungen erreichbar sein wie die Homepage.
|
||
Beide Sprachen anbieten (deutsche und englische Fassung), englische Fassung ist
|
||
für Google maßgeblich.
|
||
|
||
### 1.1 Deutsche Fassung
|
||
|
||
```markdown
|
||
## Verarbeitung von Daten aus Google-Diensten
|
||
|
||
Porta ist eine Plattform für KI-gestützte Geschäftsworkflows. Wenn Sie eine
|
||
Verbindung zu Ihrem Google-Konto herstellen, greift Porta ausschließlich auf
|
||
diejenigen Daten zu, die für die von Ihnen ausgewählte Funktionalität
|
||
erforderlich sind, und ausschließlich mit den von Ihnen über den Google-OAuth-
|
||
Consent-Bildschirm freigegebenen Berechtigungen (Scopes).
|
||
|
||
### Welche Google-Berechtigungen wir anfordern
|
||
|
||
| Scope | Wozu Porta diese Berechtigung nutzt |
|
||
|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `openid`, `userinfo.email`, `userinfo.profile` | Anmeldung an Porta (Single-Sign-On) und eindeutige Zuordnung Ihres Benutzerkontos. |
|
||
| `https://www.googleapis.com/auth/drive.readonly` | Lesezugriff auf Ihre Google-Drive-Dateien, damit Sie Dateien aus Drive im Porta-Workspace auswählen, vorschauen und der KI als Quelle übergeben können. Porta schreibt **nicht** in Ihr Drive. |
|
||
| `https://www.googleapis.com/auth/gmail.readonly` | Lesezugriff auf Ihre Gmail-Labels und -Nachrichten, damit Sie E-Mails in Porta auflisten, vorschauen und einer KI-Konversation als Quelle anhängen können. Porta versendet, ändert oder löscht **keine** E-Mails. |
|
||
|
||
### Was mit den Daten geschieht
|
||
|
||
* **Speicherung**: Porta speichert die OAuth-Refresh-Tokens verschlüsselt in
|
||
der eigenen Datenbank, um ohne erneuten Login auf Ihre freigegebenen Daten
|
||
zugreifen zu können. Inhalte aus Drive oder Gmail werden nur dann persistiert,
|
||
wenn Sie sie aktiv als „Quelle" oder „Datei" in Porta anlegen; ansonsten
|
||
werden sie nur transient für die jeweilige Anfrage geladen.
|
||
* **Verwendung**: Drive- und Gmail-Daten werden ausschließlich genutzt, um
|
||
Ihre direkten Anfragen in Porta zu beantworten (z.B. Dokument anzeigen,
|
||
durchsuchen, einer KI-Konversation beifügen, automatisierte Workflows
|
||
ausführen, die Sie selbst konfiguriert haben).
|
||
* **Keine Weitergabe**: Porta gibt Daten aus Ihrem Google-Konto **nicht** an
|
||
Dritte weiter, mit Ausnahme von Sub-Prozessoren, die für den Betrieb der
|
||
Plattform notwendig sind (Cloud-Hosting, KI-Inferenz). Diese Sub-Prozessoren
|
||
sind in Anhang A dieser Richtlinie aufgeführt und vertraglich auf den Schutz
|
||
Ihrer Daten verpflichtet.
|
||
* **Keine Werbung, kein Verkauf, kein Modelltraining**: Porta nutzt Daten
|
||
aus Ihrem Google-Konto **nicht** für personalisierte Werbung, **nicht** für
|
||
den Verkauf an Dritte und **nicht** für das Training generischer KI-Modelle.
|
||
* **Menschlicher Zugriff**: Auf Ihre Google-Daten wird kein routinemäßiger
|
||
menschlicher Zugriff genommen. Mitarbeiter der PowerOn AG können nur in den
|
||
folgenden eng begrenzten Fällen Einsicht nehmen: (a) mit Ihrer ausdrücklichen
|
||
Einwilligung, (b) zur Sicherheitsuntersuchung eines konkreten Vorfalls,
|
||
(c) zur Erfüllung gesetzlicher Verpflichtungen, oder (d) wo dies zur Behebung
|
||
eines technischen Fehlers in einer einzelnen Anfrage zwingend nötig ist.
|
||
|
||
### Limited Use Disclosure
|
||
|
||
Porta hält die Anforderungen der **Google API Services User Data Policy**
|
||
einschließlich der **Limited-Use-Anforderungen** ein.
|
||
|
||
> *Porta's use and transfer of information received from Google APIs to any
|
||
> other app will adhere to Google API Services User Data Policy, including the
|
||
> Limited Use requirements.*
|
||
> *(<https://developers.google.com/terms/api-services-user-data-policy>)*
|
||
|
||
### Verbindung trennen und Daten löschen
|
||
|
||
Sie können Ihre Google-Verbindung jederzeit beenden:
|
||
|
||
1. **In Porta**: Profil → Verbindungen → Google → „Trennen". Damit werden die
|
||
bei Porta gespeicherten OAuth-Tokens unverzüglich widerrufen und gelöscht.
|
||
2. **In Ihrem Google-Konto**: <https://myaccount.google.com/permissions> →
|
||
Porta auswählen → „Zugriff entfernen".
|
||
|
||
Auf Anfrage an `support@poweron.swiss` löschen wir innerhalb von 30 Tagen
|
||
sämtliche von Ihrem Google-Konto stammende Inhalte aus unseren Systemen
|
||
(unbeschadet gesetzlicher Aufbewahrungspflichten).
|
||
```
|
||
|
||
### 1.2 English version
|
||
|
||
```markdown
|
||
## Processing of Data from Google Services
|
||
|
||
Porta is a platform for AI-assisted business workflows. When you connect
|
||
your Google account, Porta accesses only the data that is required for the
|
||
functionality you have selected, and only within the permissions (scopes) you
|
||
have explicitly granted on the Google OAuth consent screen.
|
||
|
||
### Google permissions we request
|
||
|
||
| Scope | How Porta uses this permission |
|
||
|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `openid`, `userinfo.email`, `userinfo.profile` | Sign-in to Porta (Single Sign-On) and unambiguous identification of your user account. |
|
||
| `https://www.googleapis.com/auth/drive.readonly` | Read-only access to your Google Drive files, so that you can browse, preview and attach Drive files as sources to AI conversations and workflows in Porta. Porta does **not** write to your Drive. |
|
||
| `https://www.googleapis.com/auth/gmail.readonly` | Read-only access to your Gmail labels and messages, so that you can list, preview and attach emails as sources to AI conversations in Porta. Porta does **not** send, modify or delete emails. |
|
||
|
||
### How we handle the data
|
||
|
||
* **Storage**: Porta stores OAuth refresh tokens encrypted in its own
|
||
database in order to access your authorized data without forcing you to
|
||
re-authenticate. Content from Drive or Gmail is persisted only when you
|
||
actively register it as a "source" or "file" in Porta; otherwise it is
|
||
loaded transiently for the duration of the request only.
|
||
* **Usage**: Drive and Gmail data are used exclusively to fulfill your direct
|
||
requests within Porta (e.g., display, search, attach to an AI
|
||
conversation, run an automated workflow you yourself have configured).
|
||
* **No third-party sharing**: Porta does **not** share your Google data
|
||
with third parties, except sub-processors strictly necessary to operate the
|
||
platform (cloud hosting, AI inference). Sub-processors are listed in
|
||
Annex A of this policy and are contractually bound to protect your data.
|
||
* **No advertising, no sale, no model training**: Porta does **not** use
|
||
your Google account data for personalized advertising, **not** for sale to
|
||
third parties, and **not** to train generalized AI models.
|
||
* **Human access**: Routine human access to your Google data does not occur.
|
||
PowerOn AG personnel may access your Google data only in narrowly defined
|
||
cases: (a) with your explicit consent, (b) for security investigation of a
|
||
specific incident, (c) to comply with applicable law, or (d) where strictly
|
||
necessary to fix a technical defect in a specific request.
|
||
|
||
### Limited Use Disclosure
|
||
|
||
Porta complies with the requirements of the **Google API Services User
|
||
Data Policy**, including the **Limited Use** requirements.
|
||
|
||
> *Porta's use and transfer of information received from Google APIs to any
|
||
> other app will adhere to the Google API Services User Data Policy,
|
||
> including the Limited Use requirements.*
|
||
> *(<https://developers.google.com/terms/api-services-user-data-policy>)*
|
||
|
||
### Disconnecting and deleting your data
|
||
|
||
You may revoke your Google connection at any time:
|
||
|
||
1. **In Porta**: Profile → Connections → Google → "Disconnect". This
|
||
immediately revokes and deletes the OAuth tokens stored at Porta.
|
||
2. **In your Google account**: <https://myaccount.google.com/permissions> →
|
||
select Porta → "Remove access".
|
||
|
||
On request to `support@poweron.swiss`, we will delete all content originating
|
||
from your Google account from our systems within 30 days (subject to
|
||
statutory retention obligations).
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Justifications für jeden Scope (Verification-Formular)
|
||
|
||
Google verlangt im Antrag pro Scope eine konkrete Begründung. **Wörtlich
|
||
einkopierbar** in das Antragsformular:
|
||
|
||
### 2.1 `openid`, `userinfo.email`, `userinfo.profile`
|
||
|
||
> Required to authenticate the user into Porta via Google Single Sign-On
|
||
> and to identify their account uniquely. We display the user's email and
|
||
> name within the application; we do not use these for any other purpose.
|
||
|
||
### 2.2 `https://www.googleapis.com/auth/drive.readonly`
|
||
|
||
> Porta provides a unified data source panel where users can browse their
|
||
> own Google Drive folders and attach selected Drive files (e.g., contracts,
|
||
> reports, spreadsheets) as inputs to AI-driven conversations and to
|
||
> automation workflows they configure themselves. We need read-only access
|
||
> in order to (a) list folders and files the user owns or has shared access
|
||
> to, (b) display file metadata such as name, type and modification date in
|
||
> our source picker, and (c) download the file content on demand when the
|
||
> user explicitly attaches a file to a chat or a workflow step. We do not
|
||
> request write or full-Drive access; Porta never modifies or deletes the
|
||
> user's Drive content.
|
||
|
||
### 2.3 `https://www.googleapis.com/auth/gmail.readonly`
|
||
|
||
> Porta lets users attach individual Gmail messages as conversation
|
||
> sources to its AI assistant (for example: "summarize this email",
|
||
> "extract the invoice data from this thread") and use email content as
|
||
> input to user-configured automation workflows. We need read-only access
|
||
> in order to (a) list the user's labels in our source picker, (b) list
|
||
> messages within a chosen label with metadata (subject, sender, date), and
|
||
> (c) fetch a specific message body and attachments when the user
|
||
> explicitly selects it. We do not request modify, send or full-mailbox
|
||
> access; Porta never sends, alters or deletes the user's email.
|
||
|
||
---
|
||
|
||
## 3. Demo-Video — Drehbuch
|
||
|
||
**Format**: YouTube unlisted, Bildschirmaufzeichnung mit Voice-Over (oder
|
||
On-Screen-Text), Länge **2:30 – 4:00 min**, 1080p, Englisch (Google reviewt
|
||
auf Englisch). Mauszeiger sichtbar, ruhiger Cursor.
|
||
|
||
**Vor Aufnahme prüfen**: App in einem **frischen Inkognito-Fenster** öffnen,
|
||
mit einem **echten Google-Account** (nicht „test@…"), in der URL-Leiste
|
||
muss `porta.poweron.swiss` deutlich lesbar sein.
|
||
|
||
### Szene-für-Szene-Skript
|
||
|
||
#### Szene 1 — Homepage & App-Identität (0:00 – 0:25)
|
||
|
||
* **Bild**: Browser zeigt `https://porta.poweron.swiss`. Logo, App-Name
|
||
„Porta", kurzer Marketing-Text sichtbar.
|
||
* **Voice / On-Screen**:
|
||
> *"This is Porta, available at porta.poweron.swiss. Porta is a
|
||
> platform for AI-assisted business workflows. The OAuth client ID we are
|
||
> submitting for verification belongs to this application."*
|
||
|
||
#### Szene 2 — Sign-in starten (0:25 – 0:45)
|
||
|
||
* **Bild**: User klickt „Sign in with Google".
|
||
* **Voice / On-Screen**:
|
||
> *"To use Porta, the user signs in with their Google account."*
|
||
|
||
#### Szene 3 — OAuth-Consent-Screen (0:45 – 1:15)
|
||
|
||
* **Bild**: Google-Consent-Bildschirm öffnet sich. **Klar lesbar**:
|
||
App-Name „Porta", angeforderte Scopes (alle, einzeln aufgeführt),
|
||
Privacy-Policy- und ToS-Link.
|
||
* **Voice / On-Screen**:
|
||
> *"Here Google shows the consent screen for Porta. The user can review
|
||
> each requested permission individually: read access to Google Drive,
|
||
> read access to Gmail, and basic profile information. The user grants
|
||
> consent."*
|
||
* User klickt „Continue" / „Allow".
|
||
|
||
#### Szene 4 — Inside the app (1:15 – 1:30)
|
||
|
||
* **Bild**: Nach erfolgreichem Login zeigt Porta das Workspace-Dashboard
|
||
mit dem User-Namen oben rechts.
|
||
* **Voice / On-Screen**:
|
||
> *"After consent, the user is redirected back to Porta and is signed
|
||
> in."*
|
||
|
||
#### Szene 5 — Drive-Scope in action (1:30 – 2:15)
|
||
|
||
* **Bild**:
|
||
1. User öffnet die UDB („Unified Data Bar") → Tab „Sources".
|
||
2. Wählt die Google-Connection.
|
||
3. Klickt auf „Drive". Die Liste der Drive-Ordner und -Dateien
|
||
erscheint.
|
||
4. User wählt eine Datei (z.B. ein PDF) und klickt „Attach to chat".
|
||
5. Im Chat-Eingabefeld erscheint die Datei als Anhang-Chip. User tippt
|
||
"Summarize this document" und sendet.
|
||
6. Die KI-Antwort referenziert den Inhalt der Datei.
|
||
* **Voice / On-Screen**:
|
||
> *"Porta uses the Drive read-only scope to let the user browse their
|
||
> Drive, attach a specific file as a source for the AI conversation, and
|
||
> then have the AI process exactly that file. Porta does not modify or
|
||
> delete anything in the user's Drive."*
|
||
|
||
#### Szene 6 — Gmail-Scope in action (2:15 – 3:00)
|
||
|
||
* **Bild**:
|
||
1. Zurück in „Sources" → Google-Connection → Klick auf „Gmail".
|
||
2. Die Liste der Gmail-Labels („INBOX", „SENT", eigene Labels)
|
||
erscheint.
|
||
3. User öffnet ein Label, eine Liste von Mails (Subject, From, Date)
|
||
wird angezeigt.
|
||
4. User wählt eine Mail und klickt „Attach to chat".
|
||
5. Im Chat erscheint die Mail als Quelle. User tippt z.B. „Extract the
|
||
order details from this email" und sendet.
|
||
6. Die KI-Antwort zeigt strukturierte Felder aus der Mail.
|
||
* **Voice / On-Screen**:
|
||
> *"The Gmail read-only scope is used so the user can pick a specific
|
||
> email to feed into an AI conversation. Porta lists labels and
|
||
> messages and fetches the body only of the message the user explicitly
|
||
> selects. Porta never sends, modifies or deletes email."*
|
||
|
||
#### Szene 7 — Disconnect (3:00 – 3:30)
|
||
|
||
* **Bild**: User öffnet Profil → Connections → Google-Eintrag → klickt
|
||
„Disconnect". Bestätigungsdialog. Der Eintrag verschwindet.
|
||
* **Voice / On-Screen**:
|
||
> *"At any time, the user can disconnect their Google account in
|
||
> Porta. This immediately revokes and deletes the stored OAuth
|
||
> tokens."*
|
||
|
||
#### Szene 8 — Privacy Policy (3:30 – 3:50)
|
||
|
||
* **Bild**: Browser navigiert zu `https://porta.poweron.swiss/poweron-privacy.html`.
|
||
Scrollen zur Sektion „Processing of Data from Google Services" und zur
|
||
„Limited Use Disclosure".
|
||
* **Voice / On-Screen**:
|
||
> *"Our privacy policy at porta.poweron.swiss/poweron-privacy.html explicitly lists
|
||
> each Google scope, the purpose of each scope, and includes the Limited
|
||
> Use Disclosure as required by the Google API Services User Data Policy."*
|
||
|
||
#### Szene 9 — Outro (3:50 – 4:00)
|
||
|
||
* **Bild**: Porta-Logo, App-Name, Submission-Datum.
|
||
* **Voice / On-Screen**:
|
||
> *"Thank you for reviewing Porta for OAuth verification."*
|
||
|
||
### Aufnahme-Checkliste
|
||
|
||
* [ ] URL-Bar in jedem Frame zeigt `porta.poweron.swiss` (kein localhost,
|
||
kein staging).
|
||
* [ ] Browser-Inkognito, keine Browser-Extensions sichtbar.
|
||
* [ ] Consent-Screen zeigt korrekten App-Namen „Porta" und korrektes Logo.
|
||
* [ ] Jeder im Antrag deklarierte Scope ist in mindestens einer Szene
|
||
*aktiv genutzt* zu sehen (nicht nur erwähnt).
|
||
* [ ] Kein „Lorem-ipsum", keine Demo-Daten mit „test", „dummy", „foo".
|
||
* [ ] Audio sauber oder Sprache als On-Screen-Text eingeblendet.
|
||
* [ ] Video als **unlisted** auf YouTube hochladen, Link ins
|
||
Verification-Formular eintragen.
|
||
|
||
---
|
||
|
||
## 4. Pre-Submission-Checkliste
|
||
|
||
Vor dem (erneuten) Klick auf „Submit for verification" alles abhaken:
|
||
|
||
* [ ] Domain `poweron.swiss` in der **Google Search Console** verifiziert
|
||
(DNS-TXT, gleicher Google-Account wie OAuth-Owner).
|
||
* [ ] `https://porta.poweron.swiss` öffentlich erreichbar, HTTPS, kein
|
||
Login-Wall, beschreibt klar was Porta ist.
|
||
* [ ] `https://porta.poweron.swiss/poweron-privacy.html` öffentlich erreichbar,
|
||
enthält die beiden Sektionen aus Kapitel 1 dieses Dokuments.
|
||
* [ ] `https://porta.poweron.swiss/poweron-terms.html` öffentlich erreichbar.
|
||
* [ ] OAuth-Consent-Screen in der GCP-Console:
|
||
* App-Name „Porta", App-Logo (120×120 PNG, kein Google-Branding).
|
||
* Support-E-Mail `support@poweron.swiss`.
|
||
* Authorized domain: `poweron.swiss`.
|
||
* Application home page: `https://porta.poweron.swiss`.
|
||
* Application privacy policy link: `https://porta.poweron.swiss/poweron-privacy.html`.
|
||
* Application terms of service link: `https://porta.poweron.swiss/poweron-terms.html`.
|
||
* [ ] Scope-Liste im Consent-Screen identisch zu `googleDataScopes` in
|
||
`platform-core/modules/auth/oauthProviderConfig.py`.
|
||
* [ ] Jeder Scope hat eine Justification (Kapitel 2 dieses Dokuments).
|
||
* [ ] Demo-Video (Kapitel 3) auf YouTube unlisted, Link im Antrag.
|
||
* [ ] Developer-E-Mail `p.motsch@poweron.swiss` empfangsbereit; Eingangs-Mail
|
||
vom Trust-&-Safety-Team kommt erfahrungsgemäß innerhalb 3-5 Tagen.
|
||
|
||
---
|
||
|
||
## 5. Was tun, wenn Google rejected
|
||
|
||
Erfahrungsgemäß werden mindestens 1-2 Iterationen bis zur Approval nötig.
|
||
Häufigste Reject-Gründe und Fixes:
|
||
|
||
| Reject-Grund | Fix |
|
||
|--------------------------------------------------------|------------------------------------------------------------------------------------------------------|
|
||
| „Privacy policy does not enumerate all requested scopes" | Sektion 1.2 dieses Dokuments wörtlich übernehmen, jeden Scope aus Tabelle erwähnen. |
|
||
| „Demo video does not show scope X being used" | Eine zusätzliche Szene im Video, in der Scope X aktiv ausgeübt wird (siehe Szene 5/6). |
|
||
| „Homepage does not describe what the app does" | Auf `porta.poweron.swiss` einen klaren „What is Porta"-Block oberhalb des Login-Buttons. |
|
||
| „Brand verification — domain not verified" | Domain in Google Search Console verifizieren mit demselben Account wie OAuth-Owner. |
|
||
| „Limited Use disclosure missing" | Wörtliche Limited-Use-Klausel aus Sektion 1.2 in die Privacy-Policy aufnehmen. |
|
||
| „App requests scopes broader than necessary" | Prüfen ob `gmail.readonly` durch `gmail.metadata` ersetzt werden kann (nicht für Porta — wir lesen Inhalte). Begründen. |
|
||
|
||
Bei jedem Re-Submit nur die beanstandeten Punkte fixen, kein „While we're
|
||
at it" — das verlängert den Loop.
|
||
|
||
---
|
||
|
||
## 6. Wenn Verification durch ist
|
||
|
||
* GCP-Console → OAuth Consent Screen → Publishing Status
|
||
„**In Production**".
|
||
* Test-Users-Liste kann geleert werden (nicht nötig zu entfernen, schadet
|
||
aber auch nicht).
|
||
* Externe User sehen ab sofort keinen Warn-Bildschirm mehr, nur den
|
||
normalen, signierten Consent-Screen mit App-Logo.
|
||
* Bei jeder zukünftigen Scope-Änderung in `googleDataScopes`: erneut
|
||
durch Verification, **mit derselben Vorgehensweise**. Daher Scopes
|
||
bewusst minimal halten.
|