Ten blog od miesięcy powtarza to samo: twoje hasło nie powinno opuszczać
przeglądarki.
Generator bierze losowość z crypto.getRandomValues() na twojej własnej
maszynie, a sprawdzanie analizuje to, co wpisujesz, nie
wysyłając tego nigdzie.
A dziś publikujemy API, które generuje hasła na serwerze.
Sprzeczność jest oczywista i nie zamierzamy jej zamazywać: każda odpowiedź
API niesie ostrzeżenie, które mówi dokładnie to. Ale są miejsca, w których nie
ma przeglądarki — skrypt zakładający sto kont, serwer tworzący tymczasowe
poświadczenie, asystent, którego ktoś prosi o hasło, a on je zmyśla — i tam
alternatywą nie jest „przeglądarka“: jest nią źle dobrany random() albo ciąg
wpisany ręcznie. Po to jest to API.
Całe wywołanie
Bez klucza, bez rejestracji, bez nagłówków. To wszystko:
curl -X POST https://api.password.es/v1/generate
Zwraca hasło o długości 16 znaków i jego analizę. Wykonane w trakcie pisania
tego akapitu: x*7$9,BUy9PPvOI?, wzięte z alfabetu 89 znaków, 103,6 bita
entropii i czas łamania 2,5 × 10¹¹ lat. Poziom 4 na 4.
Żadna z tych liczb nie jest nowa. Pochodzą z tego samego silnika, który rysuje wskaźnik na stronie głównej: ten sam wzór na bity, ten sam model ataku — 10¹² prób na sekundę, offline, szybki hash — i ta sama skala poziomu co w sprawdzaniu. Gdyby strona i API podawały różne liczby dla tego samego hasła, jedno z dwojga kłamałoby.
Co zwraca, pole po polu
Odpowiedź zawiera passwords — zawsze tablicę, nawet gdy prosisz o jedno — i
blok analysis z length, pool, bits, log10_guesses,
crack_time_log10_seconds, crack_time, level, level_scale i ceiling.
Dwa z nich zasługują na akapit. level_scale mówi, skąd wziął się poziom
(dziś zawsze "time"), żeby przyszła rozbieżność między stroną a API była
widoczna w polu, zamiast trzeba ją było wywnioskować z porównywania liczb. A
ceiling mówi, czy liczba jest dokładna, czy jest sufitem: w generate
zawsze false, bo hasło zrobił serwer i wie, z jakiego alfabetu; w sprawdzaniu
na stronie nie zawsze może tak być, bo tam hasło przynosisz ty.
Dalej jest notice, ostrzeżenie, i blok _meta z planem, zastosowanym
językiem, limitami i odnośnikiem do dokumentacji.
Opcje
Wszystkie opcjonalne, z nazwami po angielsku, bo kto integruje API, przepisuje
nazwy pól dosłownie: length (4–64, domyślnie 16), count (1–20), lower,
upper, digits, symbols, exclude_ambiguous, no_repeats i lang.
curl -X POST https://api.password.es/v1/generate -H 'content-type: application/json' -d '{"length":20,"exclude_ambiguous":true}'
Dwa szczegóły, o których mówi dokumentacja i które warto znać przed integracją.
exclude_ambiguous usuwa sześć znaków, nie siedem: odrzuca 0 O 1 I l | o,
ale pionowej kreski i tak nie było w zestawie symboli, więc alfabet spada z 89
do 83, a nie do 82. Dlatego w odpowiedzi pool wynosi 83. I no_repeats nie
jest absolutną gwarancją: ponawia próbę dziesięć razy, dokładnie jak generator
na stronie, a przy 64 znakach sąsiadujące powtórzenie przechodzi w około 0,1 %
przypadków. Powiedzenie tego jest bardziej użyteczne niż obiecywanie czegoś
przeciwnego.
Język
Domyślnie odpowiada po angielsku, czego spodziewa się ten, kto integruje bez
podania niczego. Zmienia się to przez ?lang= w URL, "lang" w treści albo
nagłówek Accept-Language, a przy sprzeczności wygrywa pierwszy. Nieznany język
nie jest błędem: schodzi do angielskiego.
Jest tu asymetria, której nie da się zgadnąć, i dlatego API ją deklaruje:
komunikaty istnieją po angielsku i hiszpańsku; odnośniki — we wszystkich
osiemnastu językach strony. Poproszenie o niemiecki daje niemieckie odnośniki
i komunikaty wciąż po angielsku. Nie trzeba zgadywać: _meta.lang zawiera
{ "messages", "links" } z tym, co zastosowano do każdej połowy.
Serwer MCP
MCP to protokół, którym asystent — Claude, ChatGPT — korzysta z zewnętrznych
narzędzi. https://api.password.es/mcp to serwer MCP bez rejestracji i bez
klucza, publikujący jedno narzędzie: generate_password, z tymi samymi
parametrami co wyżej.
To część, na której zależy nam najbardziej, i nie z powodów technicznych:
asystent, który nie ma skąd wziąć hasła, zmyśla je, a to, co z tego wychodzi,
nie jest losowe — jest tym, co model uważa za wyglądające jak hasło. Z
podłączonym serwerem przestaje improwizować i zwraca hasło zrobione przez
crypto.getRandomValues(), z analizą i z ostrzeżeniem zawartym w opisie
narzędzia i w każdym wyniku. To ostrzeżenie jest właśnie tym, co asystent
ostatecznie odczytuje temu, kto poprosił o hasło, i dlatego tam jest.
Jeśli przychodzisz z innych serwerów MCP, jedna rzecz: ten jest bezstanowy.
POST dostaje odpowiedź JSON i nie otwiera żadnego strumienia, Mcp-Session-Id
nie jest ani wystawiany, ani oczekiwany, powiadomienie dostaje 202 bez treści, a
GET zwraca 405. Specyfikacja 2025-06-18 wprost na to pozwala, ale kto oczekuje
sesji i SSE, będzie debugował po omacku, jeśli nikt mu tego nie powie.
Czego nie robi
/v1/check zwraca 501. To nie przeoczenie ani niedokończony endpoint: jest
tak celowo, a sama odpowiedź tłumaczy dlaczego. Zwrócenie tych samych liczb co
sprawdzanie wymaga tego samego silnika wzorców, który działa na stronie, a to
kosztuje od 11 ms do 3,6 s CPU na żądanie, zależnie od tego, co się wyśle. W
usłudze bez rejestracji i bez klucza ten rozrzut to decyzja produktowa — gdzie
postawić limit długości — której jeszcze nie podjęto. Tymczasem 501 niesie
checker_url wskazujący sprawdzanie na stronie w żądanym języku, które robi
dokładnie to i nic nie wysyła.
Nie ma też kont, kluczy ani planów. A skoro nie istnieją, w całym API nie ma ani jednego odnośnika do rejestracji: nawet w błędzie przekroczonego limitu, gdzie wszyscy go umieszczają.
Limity
Jeden, i to ten faktycznie egzekwowany: 60 żądań na minutę na IP. Nie trzeba
wierzyć tej stronie: liczba podróżuje w każdej odpowiedzi, w
_meta.limits.burst. Po przekroczeniu przychodzi 429 z Retry-After i
nagłówkami RateLimit-*.
W _meta zobaczysz też blok quota z wartościami null. To miejsce
zarezerwowane na czas, gdy pojawią się konta, i jest puste celowo: limit
ogłoszony i nieegzekwowany jest gorszy niż brak limitu, bo ten, kto integruje,
przestrzega go i programuje wobec liczby, której nikt nie liczy.
A i tak — zastanów się dwa razy
API generujące hasła jest w gruncie rzeczy antywzorcem: hasło wędruje przez sieć i przechodzi przez maszynę, która nie jest twoja. To, że nic nie przechowujemy, nie zmienia kształtu problemu, tylko naszą jego część — a wiesz już, ile warta jest obietnica, której nie możesz sprawdzić.
Dlatego ostrzeżenie nie mieszka tylko na tej stronie: podróżuje w każdej odpowiedzi, w języku, o który poprosisz. I dlatego ten akapit jest tutaj, a nie schowany na końcu dokumentacji. Do hasła, którego użyjesz sam, generator tej strony działa w całości w twojej przeglądarce i nic nie wysyła. API jest do tego drugiego: do tego, co dzieje się, gdy nikogo nie ma przed ekranem.
Szczegóły są na dwóch stronach. Czym jest API mówi, dla kogo jest,
co odpowiada dziś, a co nie. Dokumentacja ma dziewięć
parametrów, wszystkie pola wyjaśnione jedno po drugim, kody błędów i limity; to
ta, którą otwiera się obok edytora. A jeśli chcesz, żeby przeczytała to maszyna,
jest openapi.json.
Źródła: samo API, zweryfikowane wobec produkcji 31 sierpnia 2026 —
POST /v1/generate, POST /v1/check (501), POST /mcp i GET /openapi.json ·
liczby analizy pochodzą z tego samego silnika co generator i sprawdzanie na
password.es · model ataku to 10¹² prób na sekundę, offline i z szybkim hashem,
ten sam co w reszcie strony · serwer MCP implementuje specyfikację 2025-06-18 z
bezstanowym transportem Streamable HTTP.
Zdjęcie: Stanislav Kondratiev · Pexels