Ontdek modern frontend credential management. Leer hoe u de Credential Management API, WebAuthn, Passkeys en FedCM gebruikt voor veilige, gebruiksvriendelijke login-ervaringen.
Frontend Credential Management: Een Diepgaande Blik op Wachtwoord- en Identiteits-API's
In het voortdurend evoluerende landschap van webontwikkeling blijft het inlogformulier een fundamentele, maar vaak frustrerende, gebruikersinteractie. Decennialang was de eenvoudige combinatie van gebruikersnaam en wachtwoord de poortwachter van ons digitale leven. Deze traditionele aanpak brengt echter tal van uitdagingen met zich mee: wachtwoordmoeheid, beveiligingsrisico's door zwakke of hergebruikte credentials, en een onhandige gebruikerservaring die kan leiden tot hoge bounce rates. Als ontwikkelaars balanceren we voortdurend tussen robuuste beveiliging en een frictieloze gebruikersreis.
Gelukkig is het webplatform aanzienlijk geëvolueerd. Moderne browsers worden nu geleverd met een krachtige reeks API's die speciaal zijn ontworpen om deze authenticatie-uitdagingen direct aan te pakken. Deze tools, die gezamenlijk onder de noemer Credential Management vallen, stellen ons in staat om aanmeld- en inlogervaringen te creëren die niet alleen veiliger zijn, maar ook drastisch eenvoudiger voor de eindgebruiker. Dit artikel is een uitgebreide gids voor frontend-ontwikkelaars over hoe deze API's te benutten—van de fundamentele Credential Management API tot de wachtwoordloze toekomst van WebAuthn en de privacybeschermende wereld van Federated Credential Management (FedCM).
De Oude Garde: Uitdagingen van Traditionele, op Formulieren Gebaseerde Authenticatie
Voordat we in de moderne oplossingen duiken, is het cruciaal om de problemen te begrijpen die ze oplossen. Het klassieke <form> met e-mail- en wachtwoordinvoervelden heeft het web jarenlang gediend, maar de beperkingen zijn duidelijker dan ooit in een wereld van verhoogde veiligheidsdreigingen en gebruikersverwachtingen.
- Slechte Gebruikerservaring (UX): Gebruikers moeten unieke, complexe wachtwoorden onthouden voor tientallen diensten. Dit leidt ertoe dat ze hun gegevens vergeten, wat resulteert in frustrerende processen voor het opnieuw instellen van wachtwoorden. Op mobiele apparaten is het typen van complexe wachtwoorden nog omslachtiger.
- Veiligheidsrisico's: Om met de complexiteit van wachtwoorden om te gaan, nemen gebruikers vaak hun toevlucht tot onveilige praktijken zoals het gebruik van eenvoudige, gemakkelijk te raden wachtwoorden, het hergebruiken van hetzelfde wachtwoord op meerdere sites, of het opschrijven ervan. Dit maakt hen kwetsbaar voor credential stuffing-aanvallen, waarbij aanvallers lijsten met gestolen credentials gebruiken om ongeautoriseerde toegang tot andere diensten te verkrijgen.
- Kwetsbaarheden voor Phishing: Zelfs slimme gebruikers kunnen worden misleid door geavanceerde phishing-sites die legitieme inlogpagina's nabootsen om hun gegevens te stelen. Traditionele wachtwoorden bieden hier weinig tot geen bescherming tegen.
- Hoge Ontwikkelingslast: Het bouwen van veilige authenticatiestromen vanaf nul is complex. Ontwikkelaars moeten wachtwoord-hashing en -salting afhandelen, multi-factor authenticatie (MFA) implementeren, tokens voor wachtwoordherstel beheren en zich beschermen tegen verschillende aanvallen zoals brute-forcing en timing-aanvallen.
Deze uitdagingen benadrukken de duidelijke behoefte aan een betere methode—een systeem waarin de browser en het besturingssysteem kunnen optreden als vertrouwde bemiddelaars, waardoor het proces voor de gebruiker wordt vereenvoudigd en de beveiliging voor de applicatie wordt versterkt.
De Moderne Oplossing: De Credential Management API
De Credential Management API is de hoeksteen van moderne frontend authenticatie. Het biedt een gestandaardiseerde, programmatische interface voor websites om te communiceren met de credential store van de browser. Deze store kan de ingebouwde wachtwoordmanager van de browser zijn of zelfs een gekoppelde kluis op besturingssysteemniveau. In plaats van uitsluitend te vertrouwen op de heuristiek van het automatisch invullen van HTML-formulieren, stelt deze API ontwikkelaars in staat om direct gebruikersgegevens op te vragen, aan te maken en op te slaan.
De API is toegankelijk via het navigator.credentials object in JavaScript en draait om drie belangrijke methoden: get(), create(), en store().
Belangrijkste Voordelen van de Credential Management API
- Inloggen met één tik: Voor terugkerende gebruikers maakt de API een bijna onmiddellijke inlogervaring mogelijk. De browser kan de gebruiker vragen om een opgeslagen account te selecteren, en met een enkele tik of klik worden de credentials aan de website verstrekt.
- Gestroomlijnd Aanmelden: Tijdens de registratie helpt de API door automatisch bekende informatie in te vullen en, na een succesvolle aanmelding, de gebruiker naadloos te vragen om hun nieuwe credentials op te slaan.
- Ondersteuning voor Meerdere Credential-Typen: Dit is misschien wel de krachtigste functie. De API is ontworpen om uitbreidbaar te zijn en ondersteunt niet alleen traditionele wachtwoorden (
PasswordCredential), maar ook gefedereerde identiteiten (FederatedCredential) en public-key credentials die worden gebruikt door WebAuthn (PublicKeyCredential). - Verbeterde Beveiliging: Door de interactie te bemiddelen, helpt de browser veiligheidsrisico's te beperken. Het zorgt er bijvoorbeeld voor dat credentials alleen beschikbaar zijn voor de origin (domein) waarvoor ze zijn opgeslagen, wat een inherente bescherming biedt tegen veel phishing-aanvallen.
Praktische Implementatie: Gebruikers Inloggen met `navigator.credentials.get()`
De get() methode wordt gebruikt om de credentials van een gebruiker op te halen voor het inloggen. U kunt specificeren welke soorten credentials uw applicatie ondersteunt.
Stel je voor dat een gebruiker op je inlogpagina terechtkomt. In plaats van dat ze iets moeten typen, kun je onmiddellijk controleren of ze een opgeslagen credential hebben.
async function handleSignIn() {
try {
// Controleer of de API beschikbaar is
if (!navigator.credentials) {
console.log('Credential Management API niet ondersteund.');
// Val terug op het tonen van het traditionele formulier
return;
}
const cred = await navigator.credentials.get({
// We vragen om een op wachtwoord gebaseerd credential
password: true,
// U kunt ook andere typen aanvragen, die we later zullen behandelen
});
if (cred) {
// Een credential werd geselecteerd door de gebruiker
console.log('Credential ontvangen:', cred);
// Stuur nu de credential naar uw server voor verificatie
await serverLogin(cred.id, cred.password);
} else {
// De gebruiker heeft de prompt gesloten of heeft geen opgeslagen credentials
console.log('Geen credential geselecteerd.');
}
} catch (err) {
console.error('Fout bij het ophalen van credential:', err);
// Handel fouten af, bv. toon het traditionele formulier
}
}
async function serverLogin(username, password) {
// Dit is een mock-functie. In een echte app zou u dit
// naar uw backend sturen via een POST-verzoek.
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'; // Doorsturen bij succes
} else {
// Handel mislukte login af
console.error('Login mislukt op de server.');
}
}
In dit voorbeeld activeert het aanroepen van navigator.credentials.get({ password: true }) de browser om een native UI (vaak een accountkiezer) weer te geven met alle opgeslagen credentials voor het huidige domein. Als de gebruiker er een selecteert, wordt de promise opgelost met een PasswordCredential-object dat de id (gebruikersnaam) en het password bevat. Uw applicatie kan deze informatie vervolgens naar de server sturen om het authenticatieproces te voltooien.
Praktische Implementatie: Credentials Opslaan met `navigator.credentials.store()`
Nadat een gebruiker zich succesvol heeft aangemeld of ingelogd met een traditioneel formulier (misschien als fallback), moet u aanbieden om hun credentials op te slaan voor toekomstig gebruik. De store()-methode maakt dit naadloos.
async function handleSuccessfulSignUp(username, password) {
try {
// Maak een nieuw PasswordCredential-object
const newCredential = new PasswordCredential({
id: username,
password: password,
name: 'Gebruikersweergavenaam' // Optioneel: voor de accountkiezer
});
// Sla de credential op
await navigator.credentials.store(newCredential);
console.log('Credential succesvol opgeslagen!');
// Ga verder met het doorsturen van de gebruiker of het bijwerken van de UI
window.location.href = '/welcome';
} catch (err) {
console.error('Fout bij het opslaan van credential:', err);
}
}
Wanneer deze code wordt uitgevoerd, zal de browser een niet-opdringerige prompt tonen waarin de gebruiker wordt gevraagd of hij het wachtwoord wil opslaan. Dit is een veel betere gebruikerservaring dan te vertrouwen op de soms onvoorspelbare heuristiek van de browser om een succesvolle login te detecteren en aan te bieden het wachtwoord op te slaan.
De Volgende Stap: Wachtwoordloze Authenticatie met WebAuthn en Passkeys
Hoewel de Credential Management API de ervaring rond wachtwoorden drastisch verbetert, is het uiteindelijke doel voor velen om wachtwoorden volledig te elimineren. Hier komt de Web Authentication API (WebAuthn) om de hoek kijken. WebAuthn is een W3C-standaard die wachtwoordloze, phishing-resistente authenticatie mogelijk maakt met behulp van public-key cryptografie.
U heeft wellicht de term Passkeys recentelijk gehoord. Passkeys zijn de gebruiksvriendelijke implementatie van de standaard achter WebAuthn. Een passkey is een digitaal credential dat wordt opgeslagen op het apparaat van een gebruiker (zoals een telefoon, computer of hardware beveiligingssleutel). Het wordt gebruikt om in te loggen op websites en apps zonder wachtwoord. Ze worden vaak gesynchroniseerd tussen de apparaten van een gebruiker via clouddiensten (zoals iCloud Sleutelhanger of Google Wachtwoordmanager), wat ze ongelooflijk handig maakt.
Waarom WebAuthn een Gamechanger is voor Beveiliging
- Phishing-Resistent: Een passkey is cryptografisch gebonden aan de origin van de website waar deze is aangemaakt. Dit betekent dat een passkey die is aangemaakt voor
mijn-bank.nlniet kan worden gebruikt om in te loggen op een phishing-site zoalsmijn-bank-login.nl. De browser staat dit simpelweg niet toe. - Geen Gedeelde Geheimen: Met WebAuthn genereert het apparaat van de gebruiker een publiek/privé sleutelpaar. De privésleutel verlaat nooit het beveiligde apparaat van de gebruiker (de authenticator). Alleen de publieke sleutel wordt naar de server gestuurd. Zelfs als de database van uw server wordt gecompromitteerd, zullen aanvallers geen wachtwoorden vinden om te stelen.
- Sterke Multi-Factor Authenticatie: Een passkey combineert inherent wat de gebruiker heeft (het apparaat met de privésleutel) en wat de gebruiker is (zijn vingerafdruk/gezicht) of weet (zijn apparaat-pincode). Dit voldoet vaak aan de MFA-vereisten in één enkele, eenvoudige stap.
De WebAuthn-Flow via de Credential Management API
WebAuthn wordt ook beheerd via het navigator.credentials object, met behulp van het PublicKeyCredential type. Het proces omvat twee hoofdfasen: registratie en authenticatie.
1. Registratie (Een Passkey Aanmaken)
Dit is een vereenvoudigd overzicht. De daadwerkelijke implementatie vereist zorgvuldige server-side afhandeling van cryptografische challenges.
- Client vraagt om te registreren: De gebruiker geeft aan een passkey te willen aanmaken.
- Server stuurt een challenge: Uw server genereert een unieke, willekeurige challenge en enkele configuratieopties (een
publicKeyCreationOptions-object). - Client roept `navigator.credentials.create()` aan: Uw frontend-code geeft de opties van de server door aan deze methode.
- Gebruiker geeft goedkeuring: De browser/het besturingssysteem vraagt de gebruiker om een passkey aan te maken met de authenticator van zijn apparaat (bijv. Face ID, Windows Hello of een vingerafdrukscan). De authenticator maakt een nieuw publiek/privé sleutelpaar aan.
- Client stuurt publieke sleutel naar server: De resulterende credential, die de nieuwe publieke sleutel en een ondertekende attestatie bevat, wordt teruggestuurd naar uw server voor verificatie en opslag.
const creationOptions = await fetch('/api/webauthn/register-options').then(r => r.json());
// Belangrijk: de door de server gegenereerde challenge moet worden gedecodeerd van Base64URL naar een BufferSource
creationOptions.challenge = bufferDecode(creationOptions.challenge);
creationOptions.user.id = bufferDecode(creationations.user.id);
const credential = await navigator.credentials.create({ publicKey: creationOptions });
2. Authenticatie (Inloggen met een Passkey)
- Client vraagt om in te loggen: De gebruiker wil inloggen met zijn passkey.
- Server stuurt een challenge: Uw server genereert een nieuwe willekeurige challenge en stuurt deze naar de client (binnen een
publicKeyRequestOptions-object). - Client roept `navigator.credentials.get()` aan: Deze keer gebruikt u de
publicKey-optie. - Gebruiker geeft goedkeuring: De gebruiker authenticeert met zijn apparaat. De authenticator van het apparaat gebruikt de opgeslagen privésleutel om de challenge van de server te ondertekenen.
- Client stuurt assertie naar server: De ondertekende challenge (een assertie genoemd) wordt teruggestuurd naar uw server. De server verifieert de handtekening met de opgeslagen publieke sleutel. Als deze geldig is, wordt de gebruiker ingelogd.
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 });
Opmerking: De onbewerkte WebAuthn API brengt aanzienlijke complexiteit met zich mee, vooral rond het coderen/decoderen van gegevens (zoals ArrayBuffers en Base64URL). Het wordt ten zeerste aanbevolen om een beproefde bibliotheek zoals SimpleWebAuthn of een serviceprovider te gebruiken om de lage-niveaudetails aan zowel de client- als de serverzijde af te handelen.
Privacy-First Logins: Federated Credential Management (FedCM)
Jarenlang was "Inloggen met Google/Facebook/GitHub" een populaire manier om de aanmeldingsdrempel te verlagen. Dit model wordt Gefedereerde Identiteit genoemd. Historisch gezien was dit sterk afhankelijk van mechanismen zoals redirects, pop-ups en cookies van derden voor het volgen van de inlogstatus over verschillende sites. Nu browsers third-party cookies uitfaseren om de privacy van gebruikers te verbeteren, dreigen deze traditionele stromen te breken.
De Federated Credential Management API (FedCM) is een nieuw voorstel dat is ontworpen om use cases voor gefedereerde identiteit te blijven ondersteunen op een privacybeschermende manier, zonder afhankelijk te zijn van cookies van derden.
Belangrijkste Doelen van FedCM
- Behoud van Gefedereerde Logins: Gebruikers in staat stellen om hun favoriete Identity Providers (IdP's) te blijven gebruiken om gemakkelijk in te loggen bij Relying Parties (RP's, uw website).
- Privacy Verbeteren: Voorkomen dat IdP's gebruikers passief over het web volgen zonder hun expliciete toestemming.
- Gebruikerservaring en Beveiliging Verbeteren: Een door de browser bemiddelde, gestandaardiseerde UI bieden voor gefedereerde logins, waardoor gebruikers meer transparantie en controle krijgen over welke gegevens worden gedeeld. Dit helpt ook om UI-gebaseerde phishing-aanvallen te voorkomen.
Hoe FedCM Werkt (Globaal Overzicht)
Met FedCM orkestreert de browser zelf de inlogstroom, en fungeert als een vertrouwde tussenpersoon tussen uw site (de RP) en de Identity Provider (de IdP).
- RP vraagt een credential aan: Uw website roept
navigator.credentials.get()aan, waarbij dit keer eenfederatedprovider wordt gespecificeerd. - Browser haalt manifesten op: De browser doet gesandboxte verzoeken naar een
/.well-known/web-identity-bestand op het domein van de IdP. Dit bestand vertelt de browser waar de benodigde eindpunten te vinden zijn voor het ophalen van accountlijsten en het uitgeven van tokens. - Browser toont een accountkiezer: Als de gebruiker is ingelogd bij de IdP, toont de browser zijn eigen native UI (bijv. een dropdown in de rechterbovenhoek van het scherm) met de beschikbare accounts van de gebruiker. De pagina-inhoud van de RP wordt nooit bedekt.
- Gebruiker geeft toestemming: De gebruiker selecteert een account en stemt in met het inloggen.
- Browser haalt een token op: De browser doet een laatste verzoek aan het token-eindpunt van de IdP om een ID-token te verkrijgen.
- RP ontvangt het token: De promise van
get()wordt opgelost en retourneert eenFederatedCredential-object dat het token bevat. Uw website stuurt dit token naar uw backend, die het moet valideren bij de IdP voordat een sessie voor de gebruiker wordt aangemaakt.
async function handleFedCMLogin() {
try {
const cred = await navigator.credentials.get({
federated: {
providers: ['https://accounts.google.com', 'https://facebook.com'], // Voorbeeld IdP's
// De browser zal zoeken naar een well-known manifestbestand op deze domeinen
}
});
// Indien succesvol, bevat het credential-object een token
if (cred) {
console.log('Token ontvangen:', cred.token);
// Stuur het token naar uw server voor validatie en login
await serverLoginWithToken(cred.token, cred.provider);
}
} catch (err) {
console.error('FedCM Fout:', err);
}
}
FedCM is nog een relatief nieuwe API en de browserondersteuning evolueert, maar het vertegenwoordigt de toekomstige richting voor logins van derden op het web.
Een Geünificeerde Strategie: Progressive Enhancement voor Authenticatie
Met drie verschillende soorten credentials beschikbaar, hoe moet u uw frontend-code structureren? De beste aanpak is progressive enhancement. U moet streven naar de meest moderne, veilige ervaring mogelijk, terwijl u gracieus terugvalt op oudere methoden wanneer dat nodig is.
De Credential Management API is hiervoor ontworpen. U kunt alle ondersteunde credential-typen aanvragen in een enkele get()-aanroep, en de browser zal de beste optie prioriteren en aan de gebruiker presenteren.
De Aanbevolen Authenticatie-Flow
- Geef voorrang aan Passkeys (indien beschikbaar): Voor de meest veilige en naadloze ervaring, controleer eerst of de gebruiker een passkey heeft. U kunt
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()gebruiken voor feature detectie om conditioneel een "Inloggen met Passkey"-knop te tonen. - Gebruik een Geünificeerde `get()`-aanroep: Doe een enkele aanroep naar
navigator.credentials.get()die opties bevat voorpublicKey,password, en _mogelijk_federated. De browser is hier slim in; het zal bijvoorbeeld geen wachtwoordprompt tonen als er een passkey beschikbaar is en de voorkeur heeft. - Handel het Geretourneerde Credential af: Controleer het type van het geretourneerde credential-object met
instanceofen verwerk het dienovereenkomstig. - Gracieuze Fallback: Als de gebruiker de prompt annuleert of de API-aanroep om welke reden dan ook mislukt (bijv. in een niet-ondersteunde browser), dan en alleen dan moet u het volledige, traditionele gebruikersnaam/wachtwoordformulier weergeven.
Voorbeeld: Een Geünificeerde `get()`-aanroep
async function unifiedSignIn() {
try {
// Opmerking: Deze `publicKey`- en `federated`-opties zouden van uw server komen
const publicKeyOptions = await fetch('/api/webauthn/login-options').then(r => r.json());
// ... (buffer decoding logica hier) ...
const cred = await navigator.credentials.get({
password: true,
publicKey: publicKeyOptions,
federated: {
providers: ['https://idp.example.com']
},
// 'optional' voorkomt een fout als de gebruiker geen credentials heeft
mediation: 'optional'
});
if (!cred) {
console.log('Gebruiker geannuleerd of geen credentials. Formulier wordt getoond.');
showTraditionalLoginForm();
return;
}
// Handel de credential af op basis van het type
if (cred instanceof PasswordCredential) {
console.log('Wachtwoord-credential wordt verwerkt...');
await serverLogin(cred.id, cred.password);
} else if (cred instanceof PublicKeyCredential) {
console.log('PublicKeyCredential (Passkey) wordt verwerkt...');
await serverLoginWithPasskey(cred);
} else if (cred instanceof FederatedCredential) {
console.log('FederatedCredential (FedCM) wordt verwerkt...');
await serverLoginWithToken(cred.token, cred.provider);
}
} catch (err) {
console.error('Geünificeerde inlogfout:', err);
showTraditionalLoginForm(); // Fallback bij elke fout
}
}
Globale Overwegingen en Best Practices
Houd bij het implementeren van deze moderne authenticatiestromen voor een wereldwijd publiek rekening met het volgende:
- Browserondersteuning: Controleer altijd de browsercompatibiliteit voor elke API op sites zoals caniuse.com. Zorg voor robuuste fallbacks voor gebruikers op oudere browsers om ervoor te zorgen dat niemand wordt buitengesloten.
- Server-Side Validatie is Niet-Onderhandelbaar: De frontend is een onvertrouwde omgeving. Alle credentials, tokens en asserties die van de client worden ontvangen, moeten rigoureus worden gevalideerd op de server voordat een sessie wordt aangemaakt. Deze API's verbeteren de frontend UX; ze vervangen de backend-beveiliging niet.
- Gebruikerseducatie: Concepten zoals passkeys zijn nieuw voor veel gebruikers. Gebruik duidelijke, eenvoudige taal. Overweeg het toevoegen van tooltips of links naar korte uitleg (bijv. "Wat is een passkey?") om gebruikers door het proces te leiden en vertrouwen op te bouwen.
- Internationalisatie (i18n): Hoewel de browser-native UI's doorgaans door de browserleverancier worden gelokaliseerd, moeten alle aangepaste teksten, foutmeldingen of instructies die u toevoegt, correct worden vertaald voor uw doelgroepen.
- Toegankelijkheid (a11y): Als u aangepaste UI-elementen bouwt om deze stromen te activeren (zoals aangepaste knoppen), zorg er dan voor dat ze volledig toegankelijk zijn, met de juiste ARIA-attributen, focus-statussen en toetsenbordnavigatie-ondersteuning.
Conclusie: De Toekomst is Nu
Het tijdperk waarin we uitsluitend vertrouwden op omslachtige en onveilige wachtwoordformulieren loopt ten einde. Als frontend-ontwikkelaars zijn we nu uitgerust met een krachtige set browser-API's waarmee we authenticatie-ervaringen kunnen bouwen die tegelijkertijd veiliger, privacyvriendelijker en enorm gebruiksvriendelijker zijn.
Door de Credential Management API als een geünificeerd toegangspunt te omarmen, kunnen we onze applicaties progressief verbeteren. We kunnen het gemak van wachtwoord-logins met één tik bieden, de ijzersterke beveiliging van WebAuthn en passkeys, en de op privacy gerichte eenvoud van FedCM. De reis weg van wachtwoorden is een marathon, geen sprint, maar de tools om die toekomst te bouwen zijn vandaag voor ons beschikbaar. Door deze moderne standaarden te adopteren, kunnen we niet alleen onze gebruikers verrassen, maar ook het web een veiligere plek maken voor iedereen.