Klientský portál bez účtu

Aktualizováno: · Autor: Radim Sekera

Klientovi přijde e-mail, na telefonu ťukne na odkaz a vidí stránku, která chce loga jeho firmy. Žádné heslo, které by si musel vymyslet, žádné „potvrďte svou adresu" předtím, žádná aplikace k instalaci. Nahraje tři fotky, vloží URL, zavře prohlížeč. Když se druhý den vrátí ze stejného telefonu dokončit poslední položku, stránka si stále pamatuje, kdo je a co už poslal.

Tenhle zážitek — otevřít odkaz, udělat věc, odejít — je celý cíl návrhu. Dosáhnout ho bez účtu znamená, že portál musí pořád zodpovědět všechny otázky, které by jinak řešil účet: kdo to je, smí vidět zrovna tenhle sběr podkladů, a co brání někomu jinému si ho přečíst. Tahle stránka popisuje, jak na to BriefGate odpovídá, aniž by klienta žádal o registraci — a co ta volba stojí.

Co klient zažije

  1. Zavoláte define_intake. BriefGate vytvoří portál na jedinečné adrese (https://p.briefgate.dev/8f3kqmr2) a pošle klientovi e-mailem pozvánku.
  2. Odkaz v e-mailu je ta samá adresa portálu s připojeným tokenem (?t=...) — a právě ten token ho dovnitř skutečně pustí. Holé portal_url, které vidíte v odpovědi API i v dashboardu, token neobsahuje; samo o sobě to není funkční odkaz.
  3. Klient na odkaz klikne. Prohlížeč vymění token za session cookie a klient přistane v portálu — viz Klientský portál.
  4. Vyplňuje položky a nahrává soubory, kartu může kdykoli zavřít — všechno se průběžně ukládá. Když se přes stejný odkaz vrátí později, pokračuje přesně tam, kde skončil.
  5. Když e-mail ztratí, upomínka — automatická, nebo ta, kterou spustíte nástrojem send_chase — odkaz pošle znovu (viz Upomínky).

Žádné heslo, žádné potvrzování e-mailu, žádný postup „zapomenuté heslo" k udržování na žádné straně. Ověření identity proběhlo už ve chvíli, kdy BriefGate pozvánku odeslal — adresu klienta jste zadali vy při volání define_intake.

Co to znamená technicky

Účet nahrazuje heslo (něco, co klient zná) identitou. Tady je náhradou vlastnictví odkazu — bearer credential, stejná kategorie jako session cookie nebo API klíč, jen poslaná e-mailem místo napsaná. Bezpečným pro stavbu na tom to dělají tři rozhodnutí:

Token se nikdy neukládá jako čitelný text. Magic token se odvozuje na serveru ze sběru podkladů a serverového tajemství (HMAC, ne náhodná hodnota, kterou by bylo třeba si někde schovávat); databáze vidí jen jeho hash — stejné zacházení jako u API klíčů a session tokenů portálu. Ukradený výpis databáze vydá hashe, ne funkční odkazy.

Odkaz funguje po celou dobu platnosti, ne jen jednou. Je lákavé předpokládat, že odkaz by měl přestat platit hned po prvním kliknutí. Tenhle ne: zůstává platný, dokud nedosáhne své platnosti — nastavení účtu portal_link_ttl_days, ve výchozím stavu 30 dní — a kliknutí znovu, druhý den ráno, z jiného zařízení, pořád funguje. To odpovídá tomu, jak práce reálně vypadá: klient vyplní půlku sběru podkladů, něco ho vyruší, vrátí se o pár dní později z notebooku místo z telefonu. Jednorázový odkaz by ho nechal s mrtvým odkazem a jedinou možností napsat vám o nový; odkaz, který přežije opakované použití, znamená, že „klikni znovu" prostě funguje, na jakémkoli zařízení, dokud opravdu nevyprší.

Každé odeslání platnost stejného odkazu prodlouží, místo aby ho nahrazovalo. Sběr podkladů má jeden stálý odkaz po celou dobu své existence — pozvánka, každá naplánovaná upomínka i ruční send_chase nesou identickou URL. Co se mění při každém odeslání, jsou hodiny: platnost se počítá od posledního odeslaného e-mailu k tomu sběru podkladů, takže aktivní upomínací sekvence platnost průběžně prodlužuje, místo aby odkaz uprostřed rytmu potichu vypršel. Starý e-mail ležící měsíce ve schránce pořád odkazuje na funkční odkaz — přesně do chvíle, kdy od posledního odeslaného e-mailu k tomu sběru podkladů uplyne portal_link_ttl_days.

Výsledná session je úzce ohraničená. Uplatnění odkazu dá klientovi httpOnly cookie, omezenou na cesty /portal, takže se nikdy nepošle k API, platnou 14 dní. Opravňuje přesně k jednomu sběru podkladů — ne k dalším klientovým projektům, ne k cizímu portálu. Za ní nestojí žádný širší „klientský účet", který by unikající cookie vystavil riziku.

Alternativy, které prohrály

Účet s heslem. Výchozí reflex na „dát někomu přístup k něčemu" — a pro tuhle práci špatný. Člověk, který vyplňuje sběr podkladů v BriefGate, není váš uživatel — je to zaměstnanec vašeho klienta, subdodavatel, něčí asistentka, co vyplňuje jeden formulář pro jeden projekt, ke kterému se možná už nikdy nevrátí. Žádat po něm vymyšlení hesla pro stránku, kterou navštíví jednou, vytváří přesně to tření, které má tenhle produkt odstraňovat: klient, který odskočí od registračního formuláře, taky nepošle loga. Účet je navíc trvalá zátěž — heslo, které je třeba zabezpečit, resetovat a nakonec nechat klienta opustit — pro vztah s přirozeným koncem.

Odkaz, který umře po prvním kliknutí. Často správná volba u něčeho jako e-mail na reset hesla, kde je cílem těsný, jednorázový důkaz vlastnictví schránky. Tady je to špatný tvar, protože úkolem není dokázat identitu jednou — je to umožnit někomu vrátit se napříč dny a zařízeními bez účtu, který by si mezi návštěvami pamatoval, kdo to je. Jednorázový odkaz vede každý návrat přes vás: mrtvý odkaz, klient vám napíše, vy spustíte další send_chase. To je zátěž vynalezená bezpečnostním modelem, ne ničím, co udělal klient.

E-mailové přílohy a odpověď e-mailem. Někteří konkurenti nechají klienta jen odpovědět na e-mail se ZIPem v příloze, celý portál přeskočí. Vypadá to jako méně tření, ale zahodí to všechno, co portál přináší: žádnou antivirovou kontrolu, žádné skutečné rozpoznání typu obsahu, žádnou konverzi HEIC, žádnou validaci jednotlivých položek, žádné šifrování citlivých hodnot. Každá ochrana popsaná v Bezpečnosti — antivirová kontrola, šifrování secret položek pomocí sealed boxu, podepsané odkazy ke stažení — existuje proto, že soubor nebo hodnota prošly pipeline portálu. E-mailová příloha to všechno svou podstatou obchází, a proto BriefGate nikdy nepřipojuje soubory z briefu k odchozím e-mailům ani sám (viz Brief pro klienta).

Upřímná cena

Nic z tohohle není zadarmo a stojí za to říct otevřeně, co je ten kompromis.

Kdo má odkaz, má přístup. Za odkazem do portálu nestojí žádný druhý faktor, jako u účtu s heslem a TOTP. Když klient přepošle pozvánku subdodavateli, ten teď může odesílat — a vidět — všechno, co už u sběru podkladů je. To je často přesně to, co chcete (viz Víc lidí na straně klienta pro podporovaný způsob, jak přidat druhého příjemce záměrně), ale znamená to i, že odkaz vložený do špatného Slack kanálu nebo do sdílené schránky je skutečné riziko, ne teoretické. BriefGate nemá jak poznat, jestli odkaz uplatnila osoba, které jste napsali, nebo někdo, komu ho přeposlala.

Přeposlaný e-mail přeposílá i přístup, na nějakou dobu. Protože odkaz funguje až do vypršení platnosti místo toho, aby umřel po prvním použití, stará pozvánka ve sdílené schránce zůstává živým přístupovým údajem až portal_link_ttl_days (výchozí 30 dní) — a každá další upomínka tyhle hodiny znovu natáhne, takže u sběru podkladů pod aktivním upomínáním zůstává naživu i starý přeposlaný odkaz. Nastavte retention.mode: "on_delivery" (viz Bezpečnost → Uchování a mazání) tam, kde je to okno nepříjemné, ať jsou podklady pryč dávno předtím, než by na platnosti odkazu vůbec záleželo.

Neexistuje samoobslužné obnovení přístupu. Když klient e-mail ztratí, řešení je na vás: spustit nové odeslání. Jednodušší než reset hesla, ale klient nemá vlastní cestu zpět — musí se ozvat vám, nebo počkat na další naplánovanou upomínku.

Proti účtu, který by nikdo nechtěl zakládat kvůli formuláři, který vyplní jednou, je tohle kompromis, který BriefGate dělá záměrně: chovat se k odkazu jako k přístupovému údaji, chránit ho tak, jak by se měl chránit jakýkoli bearer token — hashovaný v databázi, úzce ohraničený, s platností, kterou prodlužuje jedině BriefGate vlastním odesíláním — a smířit se s tím, že kdo ho drží, má přístup. Stejný kompromis dělá každý produkt s magic linkem — tady jen otevřeně, místo aby ho zamlčel.