Utforska modern hantering av inloggningsuppgifter i frontend. LÀr dig anvÀnda Credential Management API, WebAuthn, Passkeys och FedCM för sÀkra och anvÀndarvÀnliga inloggningsupplevelser.
Hantering av inloggningsuppgifter i frontend: En djupdykning i API:er för lösenord och identitet
I den stÀndigt förÀnderliga vÀrlden av webbutveckling Àr inloggningsformulÀret fortfarande en grundlÀggande, men ofta frustrerande, anvÀndarinteraktion. I Ärtionden har den enkla kombinationen av anvÀndarnamn och lösenord varit portvakten till vÄra digitala liv. Men detta traditionella tillvÀgagÄngssÀtt Àr fyllt av utmaningar: lösenordströtthet, sÀkerhetsrisker frÄn svaga eller ÄteranvÀnda inloggningsuppgifter och en klumpig anvÀndarupplevelse som kan leda till höga avvisningsfrekvenser. Som utvecklare navigerar vi stÀndigt den kÀnsliga balansen mellan robust sÀkerhet och en friktionsfri anvÀndarresa.
Lyckligtvis har webbplattformen utvecklats avsevĂ€rt. Moderna webblĂ€sare levereras nu med en kraftfull uppsĂ€ttning API:er som Ă€r utformade specifikt för att ta itu med dessa autentiseringsutmaningar. Dessa verktyg, som gemensamt faller under paraplybegreppet Credential Management (hantering av inloggningsuppgifter), gör det möjligt för oss att skapa registrerings- och inloggningsupplevelser som inte bara Ă€r sĂ€krare utan ocksĂ„ dramatiskt enklare för slutanvĂ€ndaren. Den hĂ€r artikeln Ă€r en omfattande guide för frontend-utvecklare om hur man utnyttjar dessa API:er â frĂ„n det grundlĂ€ggande Credential Management API till den lösenordsfria framtiden med WebAuthn och den integritetsbevarande vĂ€rlden av Federated Credential Management (FedCM).
Det gamla gardet: Utmaningar med traditionell formulÀrbaserad autentisering
Innan vi dyker in i de moderna lösningarna Àr det avgörande att förstÄ problemen de löser. Det klassiska <form> med fÀlt för e-post och lösenord har tjÀnat webben i Äratal, men dess begrÀnsningar Àr tydligare Àn nÄgonsin i en vÀrld av ökade sÀkerhetshot och anvÀndarförvÀntningar.
- DÄlig anvÀndarupplevelse (UX): AnvÀndare mÄste komma ihÄg unika, komplexa lösenord för dussintals tjÀnster. Detta leder till att de glömmer sina uppgifter, vilket resulterar i frustrerande flöden för lösenordsÄterstÀllning. PÄ mobila enheter Àr det Ànnu krÄngligare att skriva in komplexa lösenord.
- SÀkerhetsrisker: För att hantera lösenordskomplexitet tar anvÀndare ofta till osÀkra metoder som att anvÀnda enkla, lÀtta att gissa lösenord, ÄteranvÀnda samma lösenord pÄ flera webbplatser eller skriva ner dem. Detta gör dem sÄrbara för credential stuffing-attacker, dÀr angripare anvÀnder listor med stulna inloggningsuppgifter för att fÄ obehörig Ätkomst till andra tjÀnster.
- SĂ„rbarheter för nĂ€tfiske (phishing): Ăven kunniga anvĂ€ndare kan luras av sofistikerade nĂ€tfiskesidor som efterliknar legitima inloggningssidor för att stjĂ€la deras uppgifter. Traditionella lösenord erbjuder lite eller inget skydd mot detta.
- Höga utvecklingskostnader: Att bygga sÀkra autentiseringsflöden frÄn grunden Àr komplext. Utvecklare mÄste hantera hashning och saltning av lösenord, implementera multifaktorautentisering (MFA), hantera tokens för lösenordsÄterstÀllning och skydda sig mot olika attacker som brute-force och timing-attacker.
Dessa utmaningar belyser ett tydligt behov av ett bĂ€ttre sĂ€tt â ett system dĂ€r webblĂ€saren och operativsystemet kan agera som betrodda medlare, vilket förenklar processen för anvĂ€ndaren samtidigt som sĂ€kerheten för applikationen stĂ€rks.
Den moderna lösningen: Credential Management API
Credential Management API Àr hörnstenen i modern frontend-autentisering. Det tillhandahÄller ett standardiserat, programmatiskt grÀnssnitt för webbplatser att interagera med webblÀsarens lager för inloggningsuppgifter. Detta lager kan vara webblÀsarens inbyggda lösenordshanterare eller till och med ett anslutet valv pÄ operativsystemsnivÄ. IstÀllet för att enbart förlita sig pÄ HTML-formulÀrs heuristik för automatisk ifyllning, tillÄter detta API utvecklare att direkt begÀra, skapa och lagra anvÀndaruppgifter.
API:et Àr tillgÀngligt via objektet navigator.credentials i JavaScript och kretsar kring tre nyckelmetoder: get(), create() och store().
Viktiga fördelar med Credential Management API
- Inloggning med ett klick: För Äterkommande anvÀndare möjliggör API:et en nÀstan omedelbar inloggningsupplevelse. WebblÀsaren kan uppmana anvÀndaren att vÀlja ett sparat konto, och med ett enda tryck eller klick tillhandahÄlls uppgifterna till webbplatsen.
- Smidigare registrering: Vid registrering hjÀlper API:et till genom att automatiskt fylla i kÀnd information och, efter en lyckad registrering, smidigt uppmana anvÀndaren att spara sina nya inloggningsuppgifter.
- Stöd för flera typer av inloggningsuppgifter: Detta Àr kanske dess mest kraftfulla funktion. API:et Àr utformat för att vara utbyggbart och stöder inte bara traditionella lösenord (
PasswordCredential), utan Àven federerade identiteter (FederatedCredential) och public-key-uppgifter som anvÀnds av WebAuthn (PublicKeyCredential). - FörbÀttrad sÀkerhet: Genom att medla interaktionen hjÀlper webblÀsaren till att minska sÀkerhetsrisker. Till exempel sÀkerstÀller den att inloggningsuppgifter endast Àr tillgÀngliga för den origin (domÀn) för vilken de sparades, vilket ger ett inbyggt skydd mot mÄnga nÀtfiskeattacker.
Praktisk implementering: Logga in anvÀndare med `navigator.credentials.get()`
Metoden get() anvÀnds för att hÀmta en anvÀndares inloggningsuppgifter för inloggning. Du kan specificera vilka typer av uppgifter din applikation stöder.
FörestÀll dig att en anvÀndare landar pÄ din inloggningssida. IstÀllet för att de behöver skriva nÄgot kan du omedelbart kontrollera om de har en sparad inloggningsuppgift.
async function handleSignIn() {
try {
// Check if the API is available
if (!navigator.credentials) {
console.log('Credential Management API not supported.');
// Fallback to showing the traditional form
return;
}
const cred = await navigator.credentials.get({
// We are requesting a password-based credential
password: true,
// You can also request other types, which we'll cover later
});
if (cred) {
// A credential was selected by the user
console.log('Credential received:', cred);
// Now, send the credential to your server for verification
await serverLogin(cred.id, cred.password);
} else {
// The user dismissed the prompt or has no saved credentials
console.log('No credential selected.');
}
} catch (err) {
console.error('Error getting credential:', err);
// Handle errors, e.g., show the traditional form
}
}
async function serverLogin(username, password) {
// This is a mock function. In a real app, you would send
// this to your backend via a POST request.
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (response.ok) {
window.location.href = '/dashboard'; // Redirect on success
} else {
// Handle login failure
console.error('Login failed on the server.');
}
}
I detta exempel utlöser anropet navigator.credentials.get({ password: true }) webblÀsaren att visa ett native grÀnssnitt (ofta en kontovÀljare) som listar alla sparade inloggningsuppgifter för den aktuella domÀnen. Om anvÀndaren vÀljer en, löses promise-objektet med ett PasswordCredential-objekt som innehÄller id (anvÀndarnamn) och password. Din applikation kan sedan skicka denna information till servern för att slutföra autentiseringsprocessen.
Praktisk implementering: Lagra inloggningsuppgifter med `navigator.credentials.store()`
Efter att en anvÀndare har registrerat sig eller loggat in med ett traditionellt formulÀr (kanske som en reservlösning), bör du erbjuda att spara deras uppgifter för framtida bruk. Metoden store() gör detta smidigt.
async function handleSuccessfulSignUp(username, password) {
try {
// Create a new PasswordCredential object
const newCredential = new PasswordCredential({
id: username,
password: password,
name: 'User display name' // Optional: for the account chooser
});
// Store the credential
await navigator.credentials.store(newCredential);
console.log('Credential stored successfully!');
// Proceed to redirect the user or update the UI
window.location.href = '/welcome';
} catch (err) {
console.error('Error storing credential:', err);
}
}
NÀr denna kod körs kommer webblÀsaren att visa en diskret uppmaning som frÄgar anvÀndaren om de vill spara lösenordet. Detta Àr en mycket bÀttre anvÀndarupplevelse Àn att förlita sig pÄ webblÀsarens ibland oförutsÀgbara heuristik för att upptÀcka en lyckad inloggning och erbjuda att spara lösenordet.
NÀsta grÀns: Lösenordsfri autentisering med WebAuthn och Passkeys
Medan Credential Management API dramatiskt förbÀttrar upplevelsen kring lösenord, Àr det ultimata mÄlet för mÄnga att eliminera lösenord helt och hÄllet. Det Àr hÀr Web Authentication API (WebAuthn) kommer in. WebAuthn Àr en W3C-standard som möjliggör lösenordsfri, nÀtfiskesÀker autentisering med hjÀlp av public-key-kryptografi.
Du kanske har hört termen Passkeys (sÀkerhetsnycklar) nyligen. Passkeys Àr den anvÀndarvÀnliga implementeringen av standarden bakom WebAuthn. En passkey Àr en digital inloggningsuppgift som lagras pÄ en anvÀndares enhet (som en telefon, dator eller hÄrdvarusÀkerhetsnyckel). Den anvÀnds för att logga in pÄ webbplatser och appar utan lösenord. De synkroniseras ofta över en anvÀndares enheter via molntjÀnster (som iCloud Keychain eller Google Password Manager), vilket gör dem otroligt bekvÀma.
Varför WebAuthn Àr en sÀkerhetsrevolution
- NÀtfiskesÀker: En passkey Àr kryptografiskt bunden till webbplatsens origin dÀr den skapades. Det betyder att en passkey skapad för
my-bank.cominte kan anvĂ€ndas för att logga in pĂ„ en nĂ€tfiskesida sommy-bank-login.com. WebblĂ€saren tillĂ„ter det helt enkelt inte. - Inga delade hemligheter: Med WebAuthn genererar anvĂ€ndarens enhet ett par med en publik och en privat nyckel. Den privata nyckeln lĂ€mnar aldrig anvĂ€ndarens sĂ€kra enhet (autentiseraren). Endast den publika nyckeln skickas till servern. Ăven om din servers databas skulle utsĂ€ttas för ett intrĂ„ng, kommer angripare inte att hitta nĂ„gra lösenord att stjĂ€la.
- Stark multifaktorautentisering: En passkey kombinerar i sig sjÀlvt vad anvÀndaren har (enheten med den privata nyckeln) och vad anvÀndaren Àr (deras fingeravtryck/ansikte) eller vet (deras enhets-PIN). Detta uppfyller ofta MFA-krav i ett enda, enkelt steg.
WebAuthn-flödet via Credential Management API
WebAuthn hanteras ocksÄ via objektet navigator.credentials, med hjÀlp av typen PublicKeyCredential. Processen innefattar tvÄ huvudsteg: registrering och autentisering.
1. Registrering (Skapa en passkey)
Detta Àr en förenklad översikt. Den faktiska implementeringen krÀver noggrann hantering av kryptografiska utmaningar pÄ serversidan.
- Klienten begÀr att fÄ registrera sig: AnvÀndaren indikerar att de vill skapa en passkey.
- Servern skickar en utmaning: Din server genererar en unik, slumpmÀssig utmaning och nÄgra konfigurationsalternativ (ett
publicKeyCreationOptions-objekt). - Klienten anropar `navigator.credentials.create()`: Din frontend-kod skickar alternativen frÄn servern till denna metod.
- AnvÀndaren godkÀnner: WebblÀsaren/OS uppmanar anvÀndaren att skapa en passkey med sin enhets autentiserare (t.ex. Face ID, Windows Hello eller en fingeravtryckslÀsare). Autentiseraren skapar ett nytt par med en publik och en privat nyckel.
- Klienten skickar den publika nyckeln till servern: Den resulterande inloggningsuppgiften, som inkluderar den nya publika nyckeln och en signerad attestering, skickas tillbaka till din server för verifiering och lagring.
const creationOptions = await fetch('/api/webauthn/register-options').then(r => r.json());
// Important: The server-generated challenge must be decoded from Base64URL to a BufferSource
creationOptions.challenge = bufferDecode(creationOptions.challenge);
creationOptions.user.id = bufferDecode(creationations.user.id);
const credential = await navigator.credentials.create({ publicKey: creationOptions });
2. Autentisering (Logga in med en passkey)
- Klienten begÀr att fÄ logga in: AnvÀndaren vill logga in med sin passkey.
- Servern skickar en utmaning: Din server genererar en ny slumpmÀssig utmaning och skickar den till klienten (inuti ett
publicKeyRequestOptions-objekt). - Klienten anropar `navigator.credentials.get()`: Den hÀr gÄngen anvÀnder du alternativet
publicKey. - AnvÀndaren godkÀnner: AnvÀndaren autentiserar sig med sin enhet. Enhetens autentiserare anvÀnder den lagrade privata nyckeln för att signera utmaningen frÄn servern.
- Klienten skickar assertionen till servern: Den signerade utmaningen (kallad en assertion) skickas tillbaka till din server. Servern verifierar signaturen med hjÀlp av den lagrade publika nyckeln. Om den Àr giltig loggas anvÀndaren in.
const requestOptions = await fetch('/api/webauthn/login-options').then(r => r.json());
requestOptions.challenge = bufferDecode(requestOptions.challenge);
const credential = await navigator.credentials.get({ publicKey: requestOptions });
Notera: RÄa WebAuthn API medför betydande komplexitet, sÀrskilt kring kodning/avkodning av data (som ArrayBuffers och Base64URL). Det rekommenderas starkt att anvÀnda ett beprövat bibliotek som SimpleWebAuthn eller en tjÀnsteleverantör för att hantera de lÄgnivÄdetaljer pÄ bÄde klient- och serversidan.
Integritetsfokuserad inloggning: Federated Credential Management (FedCM)
I Äratal har 'Logga in med Google/Facebook/GitHub' varit ett populÀrt sÀtt att minska friktionen vid registrering. Denna modell kallas Federerad Identitet. Historiskt sett har den i hög grad förlitat sig pÄ mekanismer som omdirigeringar, popup-fönster och tredjepartscookies för att spÄra inloggningsstatus över olika webbplatser. I takt med att webblÀsare gÄr mot att fasa ut tredjepartscookies för att förbÀttra anvÀndarnas integritet, riskerar dessa traditionella flöden att sluta fungera.
Federated Credential Management API (FedCM) Àr ett nytt förslag utformat för att fortsÀtta stödja anvÀndningsfall för federerad identitet pÄ ett integritetsbevarande sÀtt, utan att förlita sig pÄ tredjepartscookies.
HuvudmÄl med FedCM
- Bevara federerade inloggningar: TillÄta anvÀndare att fortsÀtta anvÀnda sina föredragna identitetsleverantörer (IdP:er) för att enkelt logga in pÄ beroende parter (RP:er, din webbplats).
- FörbÀttra integriteten: Förhindra att IdP:er passivt spÄrar anvÀndare över webben utan deras uttryckliga samtycke.
- FörbÀttra anvÀndarupplevelse och sÀkerhet: TillhandahÄlla ett webblÀsarmedierat, standardiserat grÀnssnitt för federerade inloggningar, vilket ger anvÀndarna mer transparens och kontroll över vilken data som delas. Detta hjÀlper ocksÄ till att förhindra nÀtfiskeattacker baserade pÄ anvÀndargrÀnssnitt.
Hur FedCM fungerar (övergripande)
Med FedCM orkestrerar webblÀsaren sjÀlv inloggningsflödet och agerar som en betrodd mellanhand mellan din webbplats (RP) och identitetsleverantören (IdP).
- RP begÀr en inloggningsuppgift: Din webbplats anropar
navigator.credentials.get(), denna gÄng specificeras enfederated-leverantör. - WebblÀsaren hÀmtar manifest: WebblÀsaren gör sandlÄde-förfrÄgningar till en
/.well-known/web-identity-fil pÄ IdP:ns domÀn. Denna fil talar om för webblÀsaren var den kan hitta de nödvÀndiga slutpunkterna för att hÀmta kontolistor och utfÀrda tokens. - WebblÀsaren visar en kontovÀljare: Om anvÀndaren Àr inloggad hos IdP:n, visar webblÀsaren sitt eget native grÀnssnitt (t.ex. en rullgardinsmeny i skÀrmens övre högra hörn) som visar anvÀndarens tillgÀngliga konton. RP-sidans innehÄll döljs aldrig.
- AnvÀndaren ger sitt samtycke: AnvÀndaren vÀljer ett konto och samtycker till att logga in.
- WebblÀsaren hÀmtar en token: WebblÀsaren gör en sista förfrÄgan till IdP:ns token-slutpunkt för att fÄ en ID-token.
- RP tar emot token: Promise-objektet frÄn
get()löses och returnerar ettFederatedCredential-objekt som innehÄller token. Din webbplats skickar denna token till din backend, som mÄste validera den med IdP:n innan en session skapas för anvÀndaren.
async function handleFedCMLogin() {
try {
const cred = await navigator.credentials.get({
federated: {
providers: ['https://accounts.google.com', 'https://facebook.com'], // Example IdPs
// The browser will look for a well-known manifest file on these domains
}
});
// If successful, the credential object contains a token
if (cred) {
console.log('Received token:', cred.token);
// Send the token to your server for validation and login
await serverLoginWithToken(cred.token, cred.provider);
}
} catch (err) {
console.error('FedCM Error:', err);
}
}
FedCM Àr fortfarande ett relativt nytt API, och webblÀsarstödet utvecklas, men det representerar den framtida riktningen för tredjepartsinloggningar pÄ webben.
En enhetlig strategi: Progressiv förbÀttring för autentisering
Med tre olika typer av inloggningsuppgifter tillgÀngliga, hur ska du strukturera din frontend-kod? Den bÀsta metoden Àr progressiv förbÀttring (progressive enhancement). Du bör strÀva efter att erbjuda den mest moderna och sÀkra upplevelsen som möjligt, samtidigt som du elegant faller tillbaka pÄ Àldre metoder nÀr det Àr nödvÀndigt.
Credential Management API Àr utformat för detta. Du kan begÀra alla stödda typer av inloggningsuppgifter i ett enda get()-anrop, och webblÀsaren kommer att prioritera och presentera det bÀsta alternativet för anvÀndaren.
Det rekommenderade autentiseringsflödet
- Prioritera Passkeys (om tillgÀngligt): För den sÀkraste och smidigaste upplevelsen, kontrollera först om anvÀndaren har en passkey. Du kan anvÀnda
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()för funktionsdetektering för att villkorligt visa en 'Logga in med Passkey'-knapp. - AnvÀnd ett enhetligt `get()`-anrop: Gör ett enda anrop till
navigator.credentials.get()som inkluderar alternativ förpublicKey,passwordoch _potentiellt_federated. WebblÀsaren Àr smart med detta; den visar till exempel inte en lösenordsfrÄga om en passkey Àr tillgÀnglig och föredras. - Hantera den returnerade inloggningsuppgiften: Kontrollera typen pÄ det returnerade uppgiftsobjektet med
instanceofoch bearbeta det dÀrefter. - Elegant reservlösning: Om anvÀndaren avbryter dialogrutan eller om API-anropet misslyckas av nÄgon anledning (t.ex. i en webblÀsare som inte stöds), dÄ och endast dÄ bör du visa det fullstÀndiga, traditionella formulÀret för anvÀndarnamn/lösenord.
Exempel: Ett enhetligt `get()`-anrop
async function unifiedSignIn() {
try {
// Note: These `publicKey` and `federated` options would come from your server
const publicKeyOptions = await fetch('/api/webauthn/login-options').then(r => r.json());
// ... (buffer decoding logic here) ...
const cred = await navigator.credentials.get({
password: true,
publicKey: publicKeyOptions,
federated: {
providers: ['https://idp.example.com']
},
// 'optional' prevents an error if the user has no credentials
mediation: 'optional'
});
if (!cred) {
console.log('User cancelled or no credentials. Showing form.');
showTraditionalLoginForm();
return;
}
// Handle the credential based on its type
if (cred instanceof PasswordCredential) {
console.log('Handling password credential...');
await serverLogin(cred.id, cred.password);
} else if (cred instanceof PublicKeyCredential) {
console.log('Handling PublicKeyCredential (Passkey)...');
await serverLoginWithPasskey(cred);
} else if (cred instanceof FederatedCredential) {
console.log('Handling FederatedCredential (FedCM)...');
await serverLoginWithToken(cred.token, cred.provider);
}
} catch (err) {
console.error('Unified sign-in error:', err);
showTraditionalLoginForm(); // Fallback on any error
}
}
Globala övervÀganden och bÀsta praxis
NÀr du implementerar dessa moderna autentiseringsflöden för en global publik, tÀnk pÄ följande:
- WebblÀsarstöd: Kontrollera alltid webblÀsarkompatibilitet för varje API pÄ webbplatser som caniuse.com. TillhandahÄll robusta reservlösningar för anvÀndare pÄ Àldre webblÀsare för att sÀkerstÀlla att ingen blir utelÄst.
- Validering pÄ serversidan Àr icke-förhandlingsbar: Frontend Àr en opÄlitlig miljö. Alla inloggningsuppgifter, tokens och assertioner som tas emot frÄn klienten mÄste valideras rigoröst pÄ servern innan en session skapas. Dessa API:er förbÀttrar UX i frontend; de ersÀtter inte sÀkerheten i backend.
- AnvĂ€ndarutbildning: Koncept som passkeys Ă€r nya för mĂ„nga anvĂ€ndare. AnvĂ€nd ett tydligt och enkelt sprĂ„k. ĂvervĂ€g att lĂ€gga till verktygstips eller lĂ€nkar till korta förklaringar (t.ex. 'Vad Ă€r en passkey?') för att vĂ€gleda anvĂ€ndarna genom processen och bygga förtroende.
- Internationalisering (i18n): Medan de webblÀsar-nativa grÀnssnitten vanligtvis lokaliseras av webblÀsarleverantören, mÄste all anpassad text, felmeddelanden eller instruktioner som du lÀgger till översÀttas korrekt för dina mÄlgrupper.
- TillgÀnglighet (a11y): Om du bygger anpassade UI-element för att utlösa dessa flöden (som anpassade knappar), se till att de Àr fullt tillgÀngliga, med korrekta ARIA-attribut, fokustillstÄnd och stöd för tangentbordsnavigering.
Slutsats: Framtiden Àr hÀr
Tiden dÄ vi enbart förlitade oss pÄ krÄngliga och osÀkra lösenordsformulÀr nÀrmar sig sitt slut. Som frontend-utvecklare Àr vi nu utrustade med en kraftfull uppsÀttning webblÀsar-API:er som gör att vi kan bygga autentiseringsupplevelser som Àr samtidigt sÀkrare, mer privata och oerhört mycket mer anvÀndarvÀnliga.
Genom att anamma Credential Management API som en enhetlig ingÄngspunkt kan vi successivt förbÀttra vÄra applikationer. Vi kan erbjuda bekvÀmligheten med ett-klicks-lösenordsinloggningar, den pansarsÀkra sÀkerheten hos WebAuthn och passkeys, och den integritetsfokuserade enkelheten hos FedCM. Resan bort frÄn lösenord Àr ett maraton, inte en sprint, men verktygen för att börja bygga den framtiden Àr tillgÀngliga för oss idag. Genom att anamma dessa moderna standarder kan vi inte bara glÀdja vÄra anvÀndare utan ocksÄ göra webben till en sÀkrare plats för alla.