spinny:~/writing $ less passkeys-webauthn-passwordless-authentication.md
12Lösenord är en av de saker som vi har normaliserat bara för att vi har levt med dem i flera år. Användare glömmer dem, återanvänder dem, skriver dem där de inte borde. Team måste hantera återställningar, policyer, hash, läckor, nätfiske och support.34passkey gör inte autentisering perfekt, men de tar bort ett stort problem: servern behöver inte längre hålla en hemlighet som delas med användaren.56## Vad händer egentligen78En passkey är en legitimation baserad på WebAuthn. När användaren skapar den genererar enheten ett nyckelpar:910- en privat nyckel, som finns kvar på enheten eller i lösenordshanteraren;11- en publik nyckel som servern kan spara.1213När du loggar in frågar servern inte "berätta lösenordet". Skicka en slumpmässig utmaning. Enheten signerar den med den privata nyckeln. Servern verifierar signaturen med den publika nyckeln.1415Det är det fina: om databasen blir stulen finns det inga lösenord inuti att knäcka. Och om en användare hamnar på en falsk domän är passkey inte giltig för den domänen. Det är inte bara bekvämlighet, det är ett konkret skydd mot nätfiske.1617## Webbläsaren fungerar som en brygga1819I webbläsaren är de två huvudsakliga API:2021- `navigator.credentials.create()` för att skapa en passkey;22- `navigator.credentials.get()` för att använda den under inloggning.2324Men den viktiga logiken ligger på servern. Servern måste generera utmaningen, spara den tillfälligt, verifiera svaret, kontrollera källan och Relying Party ID, sedan skapa sessionen.2526Klientdelen borde vara nästan tråkig:2728```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());3031const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});3435await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```4142Om du kommer på att du implementerar WebAuthn-kryptering för hand, sluta. Använd ett robust bibliotek på serversidan. Felen här är inte "söta buggar", de är autentiseringshål.4344## Vad ska sparas i databasen4546Det finns ingen anledning att rädda halva världen. Vanligtvis nog:4748- ID för legitimationen;49- offentlig nyckel;50- ansluten användare;51- alla verifieringsräknare eller metadata;52- transporter, om användbara för UX;53- namn valt av användaren;54- Skapandedatum och senaste användning.5556En minimal tabell kan se ut så här:5758```sql59create table passkey_credentials (60 id uuid primary key default gen_random_uuid(),61 user_id uuid not null references users(id),62 credential_id text not null unique,63 public_key text not null,64 name text,65 created_at timestamptz not null default now(),66 last_used_at timestamptz67);68```6970Sedan skulle jag lägga till granskningsloggar och aviseringar: om någon skapar en ny passkey på mitt konto vill jag veta om det.7172## UX betyder mer än demo7374Demon av en passkey är alltid vacker: du klickar, Face ID, du är med. Den faktiska produkten är mer komplicerad.7576Någon byter telefon. Någon använder en låst företagsdator. Vissa människor förstår inte varför webbläsaren föreslår en passkey. Någon förlorar åtkomst till sin enhet.7778Det är därför jag inte skulle börja med "från och med idag inga fler lösenord för alla". Jag skulle börja så här:79801. passkey valfritt för interna användare;812. förslag att skapa en efter en lyckad inloggning;823. kontosida för att byta namn och ta bort passkey;834. klara fallback;845. gradvis utbyggnad i huvudinloggningen.8586Texten i gränssnittet ska vara enkel. "Använd din enhets låsskärm" är bättre än "autentisera med en invånare FIDO2 inloggningsuppgifter."8788## Misstag jag skulle undvika8990Generera inte utmaningar på klienten. Utmaningen skapas på servern och måste endast verifieras en gång.9192Lita inte bara på legitimations-ID. Du måste verifiera signatur, utmaning, ursprung och Relying Party ID.9394Ta inte bort fallbacks innan du har ett bra återställningsflöde. Lösenordslös behöver inte bli "om du tappar din telefon är du ute för alltid".9596Behandla inte passkey som en ren frontend-knapp. Att dölja en knapp är inte säkerhet: den verkliga verifieringen är serversidan.9798## Passkey-först eller passkey-vänlig?99100För en ny produkt kan du tänka passkey-först. För en befintlig app föredrar jag passkey-vänlig: lägg till passkey som en rekommenderad metod, mät framgång och problem och minska sedan lugnt lösenordsvikten.101102Den ideala migrationen känns inte. Användaren upptäcker att det är lättare att logga in, inte att företaget har ändrat sitt autentiseringsprotokoll.103104## Slutsats105106passkey är intressanta eftersom de förbättrar säkerheten och UX samtidigt, vilket är sällsynt. De är inte ett trollspö: återhämtning, kompatibilitet, stöd och utrullning återstår att utformas väl.107108Men den grundläggande förändringen är stark. Sluta be användarna att uppfinna och skydda hemligheter. Du låter enheten signera ett kryptografiskt bevis kopplat till din domän. Mindre mänskligt minne, mindre nätfiske, färre lösenordsåterställningar. Jag skulle säga att de är värda att ta på allvar.109110## Källor111112- [MDN: Passkeys](https://developer.mozilla.org/en-US/docs/Web/Security/Authentication/Passkeys)113- [MDN: Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)114- [W3C: Web Authentication](https://www.w3.org/TR/webauthn-3/)115- [passkeys.dev](https://passkeys.dev/)116
:Passkey och WebAuthn: logga in utan lösenord, utan magilines 1-116 (END) — press q to close