# Wer sieht was

Ein Dashboard, das jeder mit der URL lesen kann, ist ein Screenshot mit Extraschritten. Der Grund, Dashboards in einer betriebenen Plattform statt in einem Ordner mit exportiertem HTML zu halten, ist, dass die Plattform sich merkt, wer sie öffnen darf — und sich das weiter merkt, nachdem die Person, die sie gebaut hat, weitergezogen ist.

Diese Seite ist die ehrliche Landkarte dieses Modells: was es heute durchsetzt, wo es aufhört, und welche Teile Sie aus dem Code erreichen können.

## Die drei Rollen[​](#die-drei-rollen "Direkter Link zur Die drei Rollen")

Jede Mitgliedschaft in einem Konto trägt genau eine Rolle:

| Rolle       | Wert      | Was sie bedeutet                                                                      |
| ----------- | --------- | ------------------------------------------------------------------------------------- |
| **Admin**   | `admin`   | Umgeht jede Zugriffsrechte-Prüfung. Verwaltet Mitglieder, Gruppen und Berechtigungen. |
| **Creator** | `creator` | Darf erstellen und ändern. Unterliegt Zugriffsrechten.                                |
| **Viewer**  | `viewer`  | Nur lesend. Wird auf jeder Route abgelehnt, die ändert.                               |

Drei Dinge dazu lohnt es sich zu wissen, bevor Sie darum herum entwerfen.

**Die Rolle liegt auf der Mitgliedschaftszeile, nicht im Token.** Das JWT trägt keine Rollenangabe, sodass jede Rollenentscheidung ein Datenbank-Lesevorgang auf dem Konto/Benutzer-Paar ist. Das ist etwas langsamer und viel schwerer zu fälschen.

**Es schlägt geschlossen fehl.** Eine Mitgliedschaft, deren gespeicherte Rolle nicht erkannt wird — ein veralteter Wert, ein Tippfehler — löst sich zu `viewer` auf, nicht zu Admin.

**Admin ist eine Übersteuerung, kein höherer Rang.** Ein Admin ist nicht „ein Creator mit mehr Berechtigungen": Die Berechtigungsprüfung schaltet direkt auf *erlauben*, bevor überhaupt eine Berechtigung geprüft wird. Sie können einen Admin nicht aus einem Ordner aussperren.

Ein API-Schlüssel handelt als die Person, die ihn erstellt hat

Ein API-Schlüssel löst sich zu dem Benutzer auf, der ihn erstellt hat, **mit dessen Rolle**. Ein von einem Admin erzeugter Schlüssel ist ein Admin-Schlüssel, und alles unten gilt für ihn genauso, wie es für diese Person im Browser gilt. Es gibt keinen separaten, engeren Berechtigungsumfang für Schlüssel, und ein Schlüssel läuft nicht ab, wenn die Rolle seines Erstellers herabgestuft wird — widerrufen Sie den Schlüssel.

Vierundzwanzig Routen sind bewusst für Schlüssel gesperrt und benötigen eine echte Browser-Sitzung: Abrechnung und Zahlung (16 davon), die API-Schlüsselverwaltung selbst, das Lesen Ihres Abonnements, Kontolöschung, Passwortänderung, Telemetrie und das Signieren von Embed-Tokens. **Alles andere akzeptiert einen Schlüssel** — einschließlich jeder Zugriffsrechte-, Gruppen-, Ordner-, Dashboard- und Datensatz-Route.

**Eine bewusste Ausnahme.** Ein Dashboard auf `public` umzuschalten wird durch einen Kontoschalter, `apiKeysMayPublish`, freigeschaltet, der **standardmäßig `false`** ist und nur von einem Admin im Browser aktiviert werden kann. Ein Schlüssel — und damit ein Agent, der einen hält — kann also innerhalb Ihres Kontos bauen, veröffentlichen und teilen, aber standardmäßig nicht dasjenige sein, das etwas weltweit lesbar macht. Siehe [Veröffentlichen und teilen](/de/guides/publish-and-share.md#going-public-is-gated-separately-and-an-agent-cannot-do-it-alone).

## Gruppen[​](#gruppen "Direkter Link zur Gruppen")

Eine Gruppe ist eine benannte Sammlung von Benutzern innerhalb eines Kontos. Sie erteilen Berechtigungen an die Gruppe; Mitgliedschaftsänderungen berühren die Berechtigung nicht.

Zwei Einschränkungen, beide bewusst:

* **Gruppen enthalten Benutzer, keine anderen Gruppen.** Es gibt keine Verschachtelung, also keine Gruppenhierarchie, über die man nachdenken müsste.
* **Lesevorgänge stehen jedem Kontomitglied offen; Schreibvorgänge sind Admin-only.** Jedes Mitglied kann die Gruppen auflisten und sehen, wer darin ist. Nur ein Admin kann erstellen, umbenennen, löschen oder die Mitgliedschaft ändern.

Gruppen *sind* im SDK enthalten:

```
from vibedasher.models import GroupCreate, GroupUpdate



created = client.groups.create(GroupCreate(name="analytics", description="Read-only analysts"))

client.groups.update(created.group.id, GroupUpdate(user_ids_to_add=["<user-id>"]))



for g in client.groups.list().groups:

    print(g.name, g.user_count)
```

```
const created = await client.groups.create({ name: 'analytics', description: 'Read-only analysts' });

await client.groups.update(created.group.id, { userIdsToAdd: ['<user-id>'] });



const { groups } = await client.groups.list();
```

## Zugriffsrechte — die Berechtigung liegt auf dem Ordner[​](#zugriffsrechte--die-berechtigung-liegt-auf-dem-ordner "Direkter Link zur Zugriffsrechte — die Berechtigung liegt auf dem Ordner")

Das ist der wichtigste Satz auf dieser Seite, und der, der Sie am ehesten überraschen wird:

> **Eine Berechtigung nennt einen Ordner, nie ein einzelnes Dashboard oder einen einzelnen Datensatz.**

Ein Zugriffsrecht ist eine Zeile der Form:

```
(account, folder, resource type, permission, principal) → allow | deny
```

* **resource type** — `dataset` oder `viz`. Das sind die beiden, die eine Berechtigung benennen kann; siehe [Was eine Berechtigung benennen kann](#what-a-grant-can-name) für alles Übrige.
* **permission** — `view`, `edit`, `delete`, `create`.
* **principal** — ein Benutzer oder eine Gruppe.
* **allow / deny** — die beiden Zugriffstypen.

Ein Dashboard wird von einer Berechtigung abgedeckt, weil es *in* dem berechtigten Ordner liegt. Verschieben Sie es in einen anderen Ordner, wird es stattdessen von den Berechtigungen dieses Ordners geregelt. Es gibt keine dashboardbezogene Berechtigung, die verlorengehen könnte — das ist die gute Hälfte dieses Designs; die andere Hälfte ist, dass **der Ordner die kleinste Einheit ist, die Sie berechtigen können**, sodass ein Ordner, den Sie teilen, ein Ordner ist, den Sie vollständig teilen.

### Das ist keine Obergrenze dafür, wie eng ein Share sein kann[​](#that-is-not-a-ceiling-on-how-narrow-a-share-can-be "Direkter Link zur Das ist keine Obergrenze dafür, wie eng ein Share sein kann")

Der Satz oben handelt von der *Berechtigung*, nicht vom Share. Ein Ordner ist das Kleinste, was Sie in einer Berechtigung nennen können — und Sie entscheiden, was in einem Ordner liegt. Um genau ein Dashboard zu teilen, geben Sie ihm einen eigenen Ordner, und das sind drei Aufrufe, die Ihr Agent schon hat:

```
create_folder(name="Q3 board pack")

move_to_folder(resource_type="viz", resource_id=<vizId>, folder_id=<newFolderId>)

grant_access(folder_id=<newFolderId>, resource_type="viz",

             principal_id=<userId>, principal_type="user", permissions=["view"])
```

`resource_type` ist `dataset` oder `viz` beim Verschieben, `principal_type` ist `user` oder `group`, und `access_type` ist standardmäßig `allow` — `deny` ist der andere Wert, und es schlägt jedes allow.

Diese drei sind MCP-Tools, und MCP ist der unterstützte Weg dafür. **Die access-rights-Routen sind absichtlich nicht im veröffentlichten SDK und nicht in der API-Referenz** — sie sind Zugriffssteuerungs-Installation, deren Form wir nicht zugesagt haben, also existiert keine generierte Client-Methode dafür und auf keine sollte man sich verlassen. `create_folder` ist das eine der drei mit einem SDK-Zwilling, `client.folders.create`.

Ein Dashboard zu verschieben ändert, welche Berechtigungen es regeln, und sonst nichts — das Dashboard behält seine id, und [sein Link bleibt unberührt](/de/guides/publish-and-share.md). „Pro Dashboard teilen ist unmöglich" ist also der falsche Schluss aus der Ordnerregel: es sind drei Aufrufe, und der Ordner ist, wie man es ausdrückt.

### Beide Hälften einer Dashboard-Berechtigung[​](#both-halves-of-a-dashboard-grant "Direkter Link zur Beide Hälften einer Dashboard-Berechtigung")

Ein Dashboard und die Daten darunter werden von **getrennten Ressourcentypen** geregelt, ein Share, der nur einen von beiden nennt, ist also halb fertig. `viz:view` lässt jemanden das Dashboard öffnen; `dataset:view` ist das, was seine Kacheln Zahlen zurückgeben lässt. Der nächste Abschnitt ist, warum das kein Detail ist, das Sie aufschieben können.

### Wie eine Entscheidung tatsächlich getroffen wird[​](#wie-eine-entscheidung-tatsächlich-getroffen-wird "Direkter Link zur Wie eine Entscheidung tatsächlich getroffen wird")

In dieser Reihenfolge. Die erste zutreffende Regel gewinnt:

1. **Admin** → erlauben. Bedingungslos, bevor überhaupt eine Berechtigung gelesen wird.
2. **Das interne `system`-Principal** → erlauben. Das ist die eigene Worker-Identität der Plattform (Aktualisierungsjobs, geplante Läufe); es ist kein Konto, in das man sich einloggen kann.
3. **Eigentümerschaft** → erlauben. Der Benutzer, dem die Zeile gehört, kann sie immer lesen und ändern.
4. Andernfalls entscheiden die Ordnerberechtigungen, und **ein einziges Deny schlägt jedes Allow.**

Deny-gewinnt lohnt sich, präzise auszusprechen, weil es enger ist, als es klingt. Ein Deny entfernt einen Ordner aus der Menge, die Ihnen gewährt wurde — es zieht nichts von den Regeln 1–3 ab. **Sie können einen Admin nicht ablehnen, und Sie können niemanden aus einer Zeile ablehnen, die ihm gehört.** Wenn Ihr mentales Modell „Deny ist der Notausschalter" lautet, ist es das nicht: Es ist eine Subtraktion nur innerhalb der Berechtigungsebene.

### Zwei Verhaltensweisen, die Ihnen auf die Füße fallen[​](#zwei-verhaltensweisen-die-ihnen-auf-die-füße-fallen "Direkter Link zur Zwei Verhaltensweisen, die Ihnen auf die Füße fallen")

**Berechtigungen kaskadieren nicht in Unterordner.** Die Prüfung ist ein flacher Mengen-Mitgliedschaftstest auf der eigenen `folder_id` der Ressource. Ordner haben zwar eine Eltern-Kind-Beziehung, und die Benutzeroberfläche zeichnet sie als Baum — aber kein Autorisierungscode läuft diesen Baum ab. Eine Berechtigung auf *Marketing* erreicht *Marketing / Q3* **nicht**. Berechtigen Sie jeden Ordner, den Sie berechtigen wollen.

**Ein Deny auf `create` bewirkte nichts — behoben am 2026-09-08.** Die Erstellungsberechtigungsprüfung las nur die `allow`-Zeilen; sowohl das eingebaute Recht eines Creators, im Kontowurzel-Ordner oder in einem Ordner, den er besitzt, zu erstellen, als auch eine explizite `allow`-Zeile an anderer Stelle umgingen jedes `deny` vollständig. Eine explizite `create`/`deny`-Zeile eines Admins übersteuert nun beide — dieselbe Regel „ein einziges Deny schlägt jedes Allow", die der Rest dieser Seite für view/edit/delete beschreibt. Admins bleiben unablehnbar, wie bei jeder anderen Berechtigung hier.

### Wer eine Berechtigung ändern darf[​](#wer-eine-berechtigung-ändern-darf "Direkter Link zur Wer eine Berechtigung ändern darf")

Ein **Kontoadmin** oder der **Eigentümer des Ordners**, auf dem die Berechtigung liegt. Das Lesen der Berechtigungen steht jedem Kontomitglied offen: Der Freigabestatus wird in der App auf Seiten dargestellt, die jedes Mitglied öffnen kann, sodass das Lesen bewusst ungesperrt ist. Behandeln Sie die Berechtigungsliste selbst als kontoweit sichtbare Information.

## Was eine Berechtigung benennen kann[​](#what-a-grant-can-name "Direkter Link zur Was eine Berechtigung benennen kann")

**Zwei Ressourcentypen sind berechtigungsfähig: `viz` (Dashboards) und `dataset`.** Bauen Sie Ihr Governance-Modell aus diesen beiden, gehalten in Ordnern — das ist die Form, die das Modell durchsetzt, und die einzige, die der Dialog anbietet. `POST /v1/access-rights` lehnt jeden anderen Ressourcentyp mit einem `400` ab, in dem Moment, in dem Sie ihn schreiben, und nicht erst, wenn sich jemand darauf verlässt.

Drei Dinge werden von etwas anderem als einer Berechtigung regiert, und zu wissen, was wovon, ist der ganze Sinn dieses Abschnitts:

| Ressource                   | Was sie regiert                                                                                                                                                                         |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Ordner**                  | Kontomitgliedschaft für Lesezugriffe; die Rolle für Mutationen. Ein Ordner ist der Container, den eine Berechtigung *benennt*, nicht etwas, wogegen eine Berechtigung geschrieben wird. |
| **Aktualisierungszeitplan** | Eigentum plus die Kontogrenze.                                                                                                                                                          |
| **Frage**                   | Nur der Eigentümer. Eine Frage kann durch keinen Mechanismus geteilt werden.                                                                                                            |
| **Aufgabe**                 | Die ACL des *Dashboards*, zu dem sie gehört.                                                                                                                                            |
| **Verbindung**              | Ihr Eigentümer und die Administratoren des Kontos. Jeder Creator darf eine anlegen.                                                                                                     |

**Eine leere Liste sagt Ihnen, welche Art von Leere es ist.** `GET /v1/access-rights/{folder}/{type}` trägt ein `enforced`-Flag, also bedeutet `total: 0` für einen nicht berechtigungsfähigen Typ *kein Recht dieses Typs kann irgendwo existieren*, während `total: 0` für `viz` bedeutet *niemand hält eines*. Zeilen, die vor der Ablehnung geschrieben wurden, werden weiterhin gelistet und bleiben entfernbar, mit `enforced: false` daneben.

## Ein Dashboard zu teilen, ohne seine Daten zu teilen, funktioniert nicht[​](#ein-dashboard-zu-teilen-ohne-seine-daten-zu-teilen-funktioniert-nicht "Direkter Link zur Ein Dashboard zu teilen, ohne seine Daten zu teilen, funktioniert nicht")

Das ist die Frage, die das Modell *nicht* so beantwortet, wie die meisten es erwarten, also ein klarer Satz dazu: **`viz:view` allein verschafft niemandem ein funktionierendes Dashboard.**

Die Kacheln eines Dashboards holen ihre Zahlen mit `POST /v1/query`, und diese Route autorisiert **jeden beteiligten Datensatz über die Datensatz-ACL** — verweigern statt weglassen: Ein einziger Datensatz, den die Betrachterin nicht lesen darf, weist die gesamte Abfrage mit `403 query_dataset_forbidden` zurück. Sie wird nie auf der Teilmenge ausgeführt, die erlaubt *wäre*. „Die Praktikantin soll dieses Dashboard sehen, aber nicht die Daten dahinter" ergibt also ein Dashboard, dessen Kacheln fehlschlagen — kein Dashboard mit verborgenen Zahlen.

Vergeben Sie zusätzlich `dataset:view` auf dem Ordner mit den Datensätzen — `viz:view` und `dataset:view` sind ein **Paar**, und eine Berechtigung, die nur die erste trägt, ergibt ein Dashboard, dessen jede Kachel `403` liefert. Wenn die Datensätze nicht pauschal geteilt werden sollen, geben Sie ihnen einen eigenen Ordner, genau wie das Rezept oben. Oder, wenn es wirklich darum geht, ein Ergebnis zu zeigen, ohne die zugrunde liegenden Daten herauszugeben, **veröffentlichen Sie das Dashboard oder betten Sie es ein**. Beide Spuren laufen unter der Dienstidentität der Plattform und konsultieren diese ACL nie — genau deshalb können sie jemandem eine Zahl zeigen, der sie nicht abfragen darf.

## Die eigene Arbeit überprüfen[​](#die-eigene-arbeit-überprüfen "Direkter Link zur Die eigene Arbeit überprüfen")

Jedes Feld oben beschreibt eine Regel; keines sagt Ihnen, was bei *einer bestimmten Person* herauskommt, und das lässt sich aus der Liste der Vergaben nicht ablesen. Rechte setzen sich zusammen — Gruppenmitgliedschaften, ein `deny`, das jedes `allow` schlägt (auch ein über eine Gruppe geerbtes), die Trennung nach Ressourcentyp und die separate Rollenprüfung bei Mutationen — zu einem Ergebnis, das keine einzelne Liste zeigt. Das geerbte `deny` ist der entscheidende Fall: Es taucht in der gelesenen Allow-Liste nie auf, weshalb „warum sieht diese Person das nicht?" aus der Liste allein nicht zu beantworten ist.

`GET /v1/access-rights/{folder}/effective?userId=` löst das auf. Für jedes Paar aus Ressourcentyp und Berechtigung liefert es, was die ACL entscheidet, **welche Regel entschieden hat**, ob die Rolle der Person es überhaupt erlaubt, ob der Typ durchgesetzt wird, das Produkt daraus — und **die Zugriffsrechtszeile, die das Urteil erzeugt hat**, also die ID, die bei einem `deny` zu widerrufen ist. Ihr Agent hat dasselbe als `describe_effective_access`.

Es beantwortet nur die ACL-Frage und sagt das in einer `caveats`-Liste bei jeder Antwort: Es sieht keine Zeilen, die der Person *gehören* (Eigentum gilt pro Zeile und schlägt die Ordner-ACL), es weiß nichts über die Spuren für öffentliche Dashboards oder Embeds, und — siehe den Abschnitt oben — ein funktionierendes Dashboard braucht auch Rechte auf seinen Datensätzen. Über sich selbst dürfen Sie immer fragen; über jemand anderen zu fragen erfordert dieselbe Stellung wie das Ändern der ACL: Konto-Admin oder Eigentümerin des Ordners.

## Das aus dem Code erreichen[​](#das-aus-dem-code-erreichen "Direkter Link zur Das aus dem Code erreichen")

| Oberfläche                                                        | In den SDKs?                 |
| ----------------------------------------------------------------- | ---------------------------- |
| Gruppen (erstellen, auflisten, aktualisieren, Mitgliedschaft)     | **Ja** — `client.groups.*`   |
| Benutzer (auflisten, aktualisieren, Rolle, Gruppenmitgliedschaft) | **Ja** — `client.users.*`    |
| Konto                                                             | **Ja** — `client.accounts.*` |
| **Zugriffsrechte (die Berechtigungen selbst)**                    | **Nein**                     |

Zugriffsrechte sind von der generierten SDK-Oberfläche ausgeschlossen, es gibt also kein `client.accessRights` und keinen Eintrag dafür in der **[API Reference](/de/reference/vibedasher-sdk-api.md)**. Die Routen existieren und akzeptieren einen API-Schlüssel — sie sind einfach nicht Teil des veröffentlichten, versionierten Client-Vertrags, und wir sagen Ihnen das lieber, als Sie gegen eine Form bauen zu lassen, zu der wir uns nicht verpflichtet haben. Verwalten Sie Berechtigungen in der App oder über Ihren Agenten: Der MCP-Server stellt Grant-, Revoke- und List-Access-Rights-Werkzeuge bereit, die dieselben Routen unter Ihrer eigenen Identität aufrufen und derselben Admin-oder-Ordnereigentümer-Regel unterliegen.

## Zeilenbasierte Filterung: nur die Embed-Spur, und nur die Embed-Spur[​](#row-level-filtering-the-embed-lane-and-only-the-embed-lane "Direkter Link zur Zeilenbasierte Filterung: nur die Embed-Spur, und nur die Embed-Spur")

Zeilenbasierte Sicherheit ist bei Vibedasher real, aber sie lebt an einem einzigen Ort: **eingebettete Dashboards hinter einem signierten Token.**

Wenn Ihr Server ein Embed-Token ausstellt, kann er Filter an die Token-Nutzlast anhängen. Bei jeder Abfrage schreibt die Plattform jede Datensatzreferenz in eine gefilterte Unterabfrage um, sodass der Betrachter physisch keine Zeilen außerhalb seiner Slice lesen kann. Die Filter kommen **ausschließlich** aus dem verifizierten Token — nie aus dem Anfragekörper —, sodass ein Betrachter seinen eigenen Umfang nicht durch Bearbeiten einer Anfrage erweitern kann. Ein Filter, der eine Spalte benennt, die in keinem Datensatz-Schema existiert, wird mit einem `403` abgelehnt, statt still ignoriert zu werden, weil ein Filter, der still nichts bewirkt, ein Loch ist.

Drei Einschränkungen, mit denen Sie planen sollten:

* **Es gilt nur für die Embed-Spur.** Die SDK-Abfragespur hat *keine* verpflichtende Filterinjektion: Ein API-Schlüssel ist ein vertrauenswürdiger serverseitiger Aufrufer, und die Einschränkung seiner eigenen Benutzer ist Ihre Aufgabe, nicht die der Plattform.
* **Die Ordner-ACL ist nicht zeilenbasiert.** Sie entscheidet, welche Dashboards und Datensätze für Sie existieren, nicht, welche Zeilen darin Sie lesen dürfen. Das sind unterschiedliche Fragen, und Vibedasher beantwortet sie mit unterschiedlicher Mechanik.
* **Ein Dashboard, das im Browser abfragt, lässt sich überhaupt nicht einschränken — so gewollt.** Das ist die Entscheidung, die vor dem Bauen fällt, nicht danach. Ein selbst gehostetes Dashboard auf der Spur ohne Zugangsdaten — der ausgeworfene Baum, dessen `dataLane` `wasm` ist, oder alles, was Sie selbst über einem Parquet- oder JSON-Auszug gebaut haben — lädt die Daten herunter und führt jede Abfrage im Browser des Besuchers aus. Der Auszug ist über **Datensatz und Momentaufnahme adressiert, nicht über eine Abfrage**, er enthält also jede Zeile dieses Datensatzes, und jeder Besucher erhält dieselbe Datei. Es bleibt kein Server im Pfad, der ihn einengen könnte: Ein in die Seite geschriebener Filter ändert, was *gezeichnet* wird, nie, was *ausgeliefert* wurde.

Zeilenbegrenzung und die Spur ohne Zugangsdaten schließen einander aus

Der ganze Reiz dieser Spur besteht darin, dass kein Schlüssel im Bundle liegt, kein Token auszustellen ist und kein eigenes Backend laufen muss — und der Preis ist genau dieselbe Eigenschaft, von der anderen Seite betrachtet: Nichts kann einem Betrachter weniger Zeilen geben als einem anderen. Das ist keine Lücke, die geschlossen werden wird; es ist, was es bedeutet, die Daten in den Browser zu legen.

Wenn manche Betrachter weniger Zeilen sehen müssen, lassen Sie die Abfrage auf einem Server. Zwei Bauformen tun das, und beide halten die Zugangsdaten von der Seite fern: **Ihr eigenes Backend stellt ein kurzlebiges Embed-Token aus, das den Filter trägt** (die Plattform hängt dieses Prädikat an jede Abfrage an, die sie autorisiert, vor jedem Join und jeder Aggregation, sodass die Seite es nicht erweitern kann), oder **vertrauenswürdiger Servercode fragt unter einem API-Schlüssel ab** und liefert Zeilen zurück, die Sie bereits eingegrenzt haben. Erst die schnelle Spur zu wählen und sie später mit einem Filter in der Seite zu „begrenzen", ergibt ein Dashboard, das richtig aussieht, keinen Fehler auslöst und jede Zeile ausliefert.

Siehe **[Einbetten](/de/api/embedding-the-share-iframe.md)** dafür, wie ein Token ausgestellt und präsentiert wird.

## Zwei-Faktor-Authentifizierung[​](#zwei-faktor-authentifizierung "Direkter Link zur Zwei-Faktor-Authentifizierung")

E-Mail + Passwort ist der einzige Zugang zu Vibedasher, der auf einem einzigen Geheimnis beruht. Anmeldungen über Google und LinkedIn tragen den zweiten Faktor ihres Anbieters; API-Schlüssel und das CLI-Token von `vibedasher login` sind gar keine Anmeldungen. Der zweite Faktor ist daher **opt-in, pro Person, nur für die Passwort-Anmeldung**: ein sechsstelliger TOTP-Code aus einer beliebigen Authenticator-App (Google Authenticator, 1Password, Authy …), eingerichtet unter **Einstellungen → Zwei-Faktor-Authentifizierung** durch Scannen eines QR-Codes und Bestätigen eines Codes. Beim Aktivieren erhalten Sie **acht einmalige Wiederherstellungscodes**, die nur einmal angezeigt werden — ein verlorenes Telefon wird mit einem davon angemeldet.

Was sich bei der Anmeldung ändert: Nach einem korrekten Passwort erhält der Browser **keine Sitzung** — er erhält eine fünfminütige Herausforderung mit einem einzigen Zweck, die nur der Code-Schritt einlösen kann. Die API sieht diese Herausforderung nie als Berechtigungsnachweis: Sie trägt eine Audience, die die API von vornherein ablehnt, sodass sie weder gegen `api.*.vibedasher.com` wiederholt noch in das Sitzungs-Cookie eingeschleust werden kann. Fünf falsche Codes sperren die Herausforderung für fünfzehn Minuten; ein Code gilt nur einmal.

Drei Grenzen, die Sie kennen sollten:

* **Die Einrichtung ist persönlich.** Jedes Mitglied schaltet sie für das eigene Konto ein; es ist nichts, was ein Administrator für alle einschaltet.
* **OAuth-Anmeldungen werden nie herausgefordert**, absichtlich — unseren Faktor über den des Anbieters zu legen, wäre Reibung ohne Sicherheit.
* **Die Entsperrung ist eine Administrator-Aktion.** Ein Mitglied ohne Telefon und ohne Wiederherstellungscode wendet sich an einen **Konto-Administrator**, der den zweiten Faktor von der Mitgliederseite aus zurücksetzt (die Aktion wird protokolliert). Ein Eigentümer, der der einzige Administrator ist und keinen Wiederherstellungscode hat, geht über den Support.

## Eine praktische Einrichtung[​](#eine-praktische-einrichtung "Direkter Link zur Eine praktische Einrichtung")

Für ein Team von zehn Personen mit ein paar sensiblen Datensätzen:

1. Machen Sie die eine oder zwei Personen, die das Konto verwalten, zu **Admins**. Denken Sie daran, dass sie durch Berechtigungen nicht regierbar sind — das ist der Sinn der Rolle und der Grund, die Liste kurz zu halten.
2. Jeder, der baut, ist ein **Creator**; jeder, der nur liest, ist ein **Viewer**. Die Viewer-Rolle ist eine harte Ablehnung bei Änderungen, also eine echte Grenze, keine Konvention der Benutzeroberfläche.
3. Legen Sie Dashboards und Datensätze in Ordner, die widerspiegeln, wie Sie sie teilen möchten — **ein Ordner pro Zielgruppe**, nicht pro Thema. Der Ordner ist die Berechtigung.
4. Erteilen Sie Berechtigungen an **Gruppen**, nicht an Personen. Die Berechtigung überlebt dann, dass jemand beitritt oder das Team verlässt.
5. Erstellen Sie keine verschachtelten Ordner und erwarten Sie nicht, dass die Berechtigung des übergeordneten Ordners sie erreicht. Berechtigen Sie jeden einzeln.
6. Wenn ein Dashboard an Personen außerhalb des Kontos gehen muss, veröffentlichen Sie es und betten Sie es mit einem signierten Token ein, das deren Zeilenfilter trägt — geben Sie ihnen kein Konto.
