Passkey nedir ve neden önemlidir?
Parolasız kimlik doğrulama, son yılların en önemli güvenlik trendlerinden biri. Passkey teknolojisi (WebAuthn/FIDO2), kimlik doğrulamayı klasik parolaların ötesine taşıyarak kimlik avına dayanıklı ve kullanıcı dostu bir deneyim sunuyor. Apple, Google ve Microsoft’un ekosistemleriyle entegre çalışan passkey’ler; cihazdaki güvenli donanım veya güvenli alanı kullanarak anahtar çifti üretir ve web sitelerine girişte yalnızca özel anahtar cihazda kalır. Böylece kullanıcılar Touch ID/Face ID, Windows Hello veya Android’in biyometrik yöntemleriyle tek dokunuşla güvenli giriş yapabilir.
Nasıl çalışır? (Kısa teknik özet)
Passkey, tarayıcıların sunduğu WebAuthn API üzerinden etkileşim kurar. Site (Relying Party), kayıt sırasında tarayıcıya bir “challenge” ve alan adı (rpID) gönderir. Kullanıcının cihazı bir anahtar çifti üretir; genel anahtar sunucuya kaydedilir, özel anahtar cihazda kalır. Giriş esnasında sunucu yeni bir “challenge” üretir; cihaz bu “challenge”ı özel anahtarla imzalar ve sunucu imzayı doğrular. Bu yapı sayesinde şifre sızması, parola doldurma saldırıları ve kimlik avı riskleri önemli ölçüde azalır.
Önkoşullar ve mimari
Bu rehberde Next.js 14 (App Router) üzerinde örnek bir passkey akışı kuracağız. İhtiyacınız olanlar: Node.js 18+, Next.js projesi, HTTPS (geliştirirken localhost desteklenir), bir veritabanı (ör. PostgreSQL, MongoDB) ve WebAuthn yardımcı kütüphaneleri. Üretimde rpID değeriniz, gerçek alan adınız (ör. example.com) olmalı; doğrulama başarısızlıklarının büyük kısmı rpID/domain uyumsuzluğundan kaynaklanır.
Adım 1: Kurulum ve bağımlılıklar
Örnek projeyi başlatmak için npx create-next-app@latest passkey-demo komutunu kullanın. Ardından sunucu ve istemci tarafı için popüler bir yardımcı set olan @simplewebauthn/server ve @simplewebauthn/browser paketlerini ekleyin: npm i @simplewebauthn/server @simplewebauthn/browser. Ortam değişkenleri için RP_NAME ve RP_ID tanımlayın (ör. RP_NAME="Passkey Demo", RP_ID="localhost" veya üretimde example.com).
Adım 2: Kayıt (Registration) akışı
Kayıt akışı iki uç noktadan oluşur: seçenek üretimi ve doğrulama. Sunucuda önce generateRegistrationOptions ile kullanıcıya özel bir challenge ve seçenekler oluşturulur. Örnek kullanım: const opts = generateRegistrationOptions({ rpName, rpID, userID, userName, attestationType: 'none', authenticatorSelection: { residentKey: 'preferred', userVerification: 'preferred' } }). Bu opts istemciye döndürülür ve tarayıcıda startRegistration(opts) çağrısı yapılır. Tarayıcı, cihazın güvenli alanında anahtar çifti üretir ve sonucu (credential) sunucuya gönderir.
Doğrulama aşamasında sunucuda verifyRegistrationResponse ile imza ve köken (origin) kontrolü yapılır. Başarılıysa kullanıcının hesabına credentialID, publicKey, signCount gibi alanları kaydedin. Birden fazla cihaza passkey eklenmesini desteklemek için kullanıcı başına birden çok credential saklamak iyi bir pratiktir.
Adım 3: Giriş (Authentication) akışı
Giriş için benzer şekilde önce generateAuthenticationOptions çağrılır. Kullanıcıya ait credential’lar biliniyorsa allowCredentials listesi ile sınırlandırabilir veya cihazın keşfedilebilir kimlik bilgilerini (discoverable credentials) desteklemek için boş bırakabilirsiniz. İstemci tarafında startAuthentication(opts) çalıştırılır ve elde edilen yanıt sunucuya doğrulama için gönderilir.
Sunucuda verifyAuthenticationResponse ile imza, challenge, origin, rpID ve sayacın (signCount) ilerleyişi kontrol edilir. Başarılı doğrulamada kullanıcı oturumunu başlatın ve credential’ın signCount değerini güncelleyin. Geriye dönük saldırıları önlemek için aynı imzayı tekrar kabul etmeyin.
İyi uygulamalar (Security + UX)
- HTTPS zorunludur: Üretimde daima HTTPS kullanın; rpID alan adınız ile origin (ör. https://example.com) örtüşmelidir. Geliştirmede localhost istisna olarak desteklenir.
- Biyometrik doğrulama: userVerification: 'required' seçeneği güvenliği artırır ancak bazı eski cihazlarda uyumluluğu azaltabilir. Dengeli yaklaşım için 'preferred' iyi bir başlangıçtır.
- Platform ve geçiş anahtarları: Kullanıcılara hem cihaz içi (platform) hem de harici güvenlik anahtarlarıyla kayıt seçeneği sunun.
- Hesap kurtarma: Passkey harika bir deneyim sunar; yine de e‑posta tabanlı oturum açma bağlantısı veya sınırlı süreli OTP gibi bir kurtarma kanalı tutun.
- Çoklu cihaz: iCloud Anahtar Zinciri veya Google Password Manager senkronizasyonu sayesinde kullanıcı farklı cihazlardan giriş yapabilir; bu durumda kullanıcı akışını basit ve yönlendirici metinlerle destekleyin.
Test, hata ayıklama ve dağıtım
Geliştirme sırasında WebAuthn’ı about://webauthn veya Chrome’un Geliştirici Araçları altındaki Sanal Kimlik Doğrulayıcı ile test edebilirsiniz. Gerçek cihaz testi için ngrok gibi tünelleme araçlarıyla geçici bir HTTPS alan adı edinip RP_ID’yi bu alan adına ayarlayın. iOS 16+, Android 9+ ve modern masaüstü tarayıcılar passkey’i destekler. Üretime alırken CORS, SameSite ve Secure bayraklı çerez ayarlarını kontrol edin; kimlik doğrulama uç noktalarınızı rate limit ve CSRF koruması ile güçlendirin.
Sık karşılaşılan hatalar ve çözümleri
- Invalid Relying Party ID: rpID ile sitenin alan adı eşleşmiyordur. Alt alan adlarında rpID üst etki alanı olabilir (ör. app.example.com için example.com).
- NotAllowedError: Kullanıcı tarayıcı diyalogunu iptal etmiştir veya zaman aşımı yaşanmıştır. İstemci tarafında daha anlaşılır hata mesajları ve tekrar dene düğmesi gösterin.
- User verification required: Sunucuda userVerification 'required' iken cihaz biyometrik doğrulama sunmuyorsa 'preferred' ile test edin.
- Counter mismatch: signCount geriye düştüyse credential’ı güvenlik gerekçesiyle askıya alın ve kullanıcıdan yeniden kayıt isteyin.
Sonuç
Passkey, güvenliği artırırken kullanıcı deneyimini hızlandıran güçlü bir yaklaşım. Next.js ile WebAuthn/FIDO2 entegrasyonu birkaç uç nokta ve doğru yapılandırmayla kısa sürede hayata geçebilir. Bu rehberdeki adımlarla kayıt ve giriş akışlarını kurabilir, üretimde HTTPS, rpID, sayım ve köken kontrolleriyle sisteminizi sertleştirebilirsiniz. Parolasız geleceğe geçiş için en iyi zaman, kullanıcılarınız hazır ve modern tarayıcılar destekliyorken bugündür.