Die API von password.es antwortet: so wird sie benutzt

Veröffentlicht am von David Carrero

Dieses Blog wiederholt seit Monaten dasselbe: dein Passwort sollte deinen Browser nicht verlassen. Der Generator holt seinen Zufall aus crypto.getRandomValues() auf deiner eigenen Maschine, und der Passwort-Checker analysiert, was du tippst, ohne es irgendwohin zu schicken.

Und heute veröffentlichen wir eine API, die Passwörter auf einem Server erzeugt.

Der Widerspruch ist offensichtlich, und wir werden ihn nicht beschönigen: Jede Antwort der API trägt einen Hinweis, der genau das sagt. Aber es gibt Stellen, an denen es keinen Browser gibt — ein Skript, das hundert Konten anlegt, ein Server, der eine temporäre Zugangsdatei erzeugt, ein Assistent, den jemand nach einem Passwort fragt und der es sich ausdenkt — und dort ist die Alternative nicht „der Browser“: Sie ist ein schlecht gewähltes random() oder eine von Hand getippte Zeichenkette. Dafür ist das hier da.

Der ganze Aufruf

Ohne Schlüssel, ohne Anmeldung, ohne Header. Das ist alles:

curl -X POST https://api.password.es/v1/generate

Zurück kommt ein Passwort mit 16 Zeichen und seine Analyse. Ausgeführt, während dieser Absatz geschrieben wurde: x*7$9,BUy9PPvOI?, aus einem Alphabet von 89 Zeichen, 103,6 Bit Entropie und eine Knackzeit von 2,5 × 10¹¹ Jahren. Stufe 4 von 4.

Keine dieser Zahlen ist neu. Sie kommen aus derselben Maschinerie, die den Balken auf der Startseite zeichnet: dieselbe Bit-Formel, dasselbe Angriffsmodell — 10¹² Versuche pro Sekunde, offline, schneller Hash — und dieselbe Stufenskala wie der Checker. Wenn Website und API für dasselbe Passwort verschiedene Zahlen lieferten, würde eine von beiden lügen.

Was zurückkommt, Feld für Feld

Die Antwort enthält passwords — immer ein Array, auch wenn du nur eines anforderst — und einen Block analysis mit length, pool, bits, log10_guesses, crack_time_log10_seconds, crack_time, level, level_scale und ceiling.

Zwei davon verdienen einen Absatz. level_scale sagt, woher die Stufe kommt (heute immer "time"), damit eine künftige Abweichung zwischen Website und API im Feld sichtbar wird, statt aus dem Vergleich von Zahlen erschlossen werden zu müssen. Und ceiling sagt, ob die Zahl exakt oder eine Obergrenze ist: bei generate steht dort immer false, weil der Server das Passwort gemacht hat und sein Alphabet kennt; beim Checker der Website geht das nicht immer, denn dort bringst du das Passwort mit.

Dann folgen notice, der Hinweis, und ein Block _meta mit dem Plan, der angewendeten Sprache, den Limits und einem Link zurück zur Dokumentation.

Die Optionen

Alle optional, und auf Englisch benannt, weil wer eine API einbindet, die Feldnamen genau so abtippt: length (4–64, Standard 16), count (1–20), lower, upper, digits, symbols, exclude_ambiguous, no_repeats und lang.

curl -X POST https://api.password.es/v1/generate -H 'content-type: application/json' -d '{"length":20,"exclude_ambiguous":true}'

Zwei Details, die die Dokumentation nennt und die man vor dem Einbinden kennen sollte. exclude_ambiguous entfernt sechs Zeichen, nicht sieben: Es wirft 0 O 1 I l | o heraus, aber der senkrechte Strich war von vornherein nicht im Symbolsatz, also sinkt das Alphabet von 89 auf 83 und nicht auf 82. Deshalb steht in der Antwort pool 83. Und no_repeats ist keine absolute Garantie: Es versucht es zehnmal, genau wie der Generator der Website, und bei 64 Zeichen rutscht eine unmittelbare Wiederholung in etwa 0,1 % der Fälle durch. Das zu sagen ist nützlicher, als das Gegenteil zu versprechen.

Die Sprache

Standardmäßig antwortet sie auf Englisch, was erwartet, wer ohne weitere Angabe einbindet. Ändern lässt sich das mit ?lang= in der URL, mit "lang" im Body oder mit dem Header Accept-Language; widersprechen sie sich, gewinnt das erste. Eine unbekannte Sprache ist kein Fehler: Sie fällt auf Englisch zurück.

Hier gibt es eine Asymmetrie, die man nicht erraten kann, und deshalb erklärt die API sie: Die Meldungen gibt es auf Englisch und Spanisch; die Links in allen achtzehn Sprachen der Website. Wer Deutsch anfordert, bekommt deutsche Links und Meldungen weiterhin auf Englisch. Man muss nichts vermuten: _meta.lang liefert { "messages", "links" } mit dem, was auf jede Hälfte angewendet wurde.

Der MCP-Server

MCP ist das Protokoll, mit dem ein Assistent — Claude, ChatGPT — externe Werkzeuge benutzt. https://api.password.es/mcp ist ein MCP-Server ohne Anmeldung und ohne Schlüssel, und er veröffentlicht ein einziges Werkzeug: generate_password, mit denselben Parametern wie oben.

Das ist der Teil, der uns am wichtigsten ist, und zwar nicht aus technischen Gründen: Ein Assistent, der nirgends ein Passwort herbekommt, denkt sich eines aus, und was dabei herauskommt, ist nicht zufällig, sondern das, was das Modell für passwortförmig hält. Mit angeschlossenem Server hört er auf zu improvisieren und gibt eines zurück, das mit crypto.getRandomValues() erzeugt wurde — mit Analyse und mit dem Hinweis, der in der Werkzeugbeschreibung und in jedem Ergebnis steckt. Genau diesen Hinweis liest der Assistent am Ende demjenigen vor, der nach dem Passwort gefragt hat, und deshalb steht er dort.

Wenn du von anderen MCP-Servern kommst, eine Sache: dieser ist zustandslos. Der POST wird mit JSON beantwortet und öffnet keinen Stream, Mcp-Session-Id wird weder ausgegeben noch erwartet, eine Notification bekommt 202 ohne Body, und GET liefert 405. Die Spezifikation 2025-06-18 erlaubt das ausdrücklich, aber wer Sitzungen und SSE erwartet, debuggt im Blindflug, wenn es ihm niemand sagt.

Was sie nicht kann

/v1/check liefert 501. Das ist weder ein Versehen noch ein halbfertiger Endpunkt: Es ist Absicht, und die Antwort selbst erklärt, warum. Dieselben Zahlen wie der Checker zu liefern, verlangt genau dieselbe Mustererkennung, die auf der Website läuft, und die kostet je nach Eingabe zwischen 11 ms und 3,6 s CPU pro Anfrage. Bei einem Dienst ohne Anmeldung und ohne Schlüssel ist diese Spanne eine Produktentscheidung — wo die Längenobergrenze liegt —, die noch nicht gefallen ist. Bis dahin trägt der 501 ein checker_url, das auf den Checker der Website in der angeforderten Sprache zeigt, der genau das tut, ohne etwas zu senden.

Konten gibt es ebenfalls nicht, auch keine Schlüssel und keine Tarife. Und weil es sie nicht gibt, findet sich in der ganzen API kein einziger Link zu einer Registrierung: nicht einmal im Fehler bei überschrittenem Limit, wo ihn alle hinsetzen.

Die Limits

Eines, und es ist das, was wirklich durchgesetzt wird: 60 Anfragen pro Minute und IP. Man muss dieser Seite nicht glauben: Die Zahl reist in jeder Antwort mit, in _meta.limits.burst. Wer darüber liegt, bekommt einen 429 mit Retry-After und RateLimit-*-Headern.

In _meta steht außerdem ein Block quota mit Werten auf null. Das ist der reservierte Platz für den Tag, an dem es Konten gibt, und er bleibt absichtlich leer: Ein angekündigtes und nicht durchgesetztes Limit ist schlimmer als gar keines, denn wer einbindet, hält sich daran und programmiert gegen eine Zahl, die niemand zählt.

Und trotzdem: zweimal überlegen

Eine API, die Passwörter erzeugt, ist im Kern ein Antipattern: Das Passwort läuft über das Netz und durch eine Maschine, die nicht deine ist. Dass wir nichts speichern, ändert nicht die Form des Problems, nur unseren Anteil daran — und du weißt bereits, was ein Versprechen wert ist, das du nicht überprüfen kannst.

Deshalb lebt der Hinweis nicht nur auf dieser Seite: Er reist in jeder Antwort mit, in der angeforderten Sprache. Und deshalb steht dieser Absatz hier und nicht versteckt am Ende der Dokumentation. Für ein Passwort, das du selbst benutzen wirst, läuft der Generator dieser Website vollständig in deinem Browser und schickt nichts. Die API ist für das andere: für das, was ohne jemanden vor einem Bildschirm passiert.

Die Details stehen auf zwei Seiten. Was die API ist erklärt, für wen sie gedacht ist, was heute antwortet und was nicht. Die Referenz hat die neun Parameter, alle Felder einzeln erklärt, die Fehlercodes und die Limits; das ist die Seite, die man neben dem Editor offen hat. Und wenn eine Maschine es lesen soll, gibt es openapi.json.


Quellen: die API selbst, am 31. August 2026 gegen die Produktion geprüft — POST /v1/generate, POST /v1/check (501), POST /mcp und GET /openapi.json · die Zahlen der Analyse stammen aus derselben Maschinerie wie Generator und Checker von password.es · das Angriffsmodell sind 10¹² Versuche pro Sekunde, offline und mit schnellem Hash, dasselbe wie im Rest der Website · der MCP-Server implementiert die Spezifikation 2025-06-18 mit zustandslosem Streamable-HTTP-Transport.

Foto von Stanislav Kondratiev · Pexels

← Zurück zum Blog