web güvenliği etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
web güvenliği etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

2 Aralık 2025 Salı

Passkey (WebAuthn/FIDO2) ile Parolasız Giriş: Next.js Üzerinde Adım Adım Kurulum

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.

20 Kasım 2025 Perşembe

Passkey (WebAuthn) ile Şifresiz Giriş Uygulaması: Adım Adım Geliştirici Rehberi

Giriş

Şifresiz kimlik doğrulama, hem güvenliği artırmak hem de kullanıcı deneyimini iyileştirmek için son yılların en önemli trendlerinden biri. Passkey (WebAuthn/FIDO2) yaklaşımı, parola sızıntılarını ve kimlik avı risklerini azaltırken tek dokunuşla giriş deneyimi sunuyor. Bu yazıda, modern bir web uygulamasına passkey tabanlı şifresiz girişi nasıl entegre edebileceğinizi adım adım ele alacağız. Anlatım sade, SEO uyumlu ve güncel standartları takip edecek şekilde hazırlandı.

Passkey Nedir ve Neden Önemlidir?

Passkey, FIDO2 ve WebAuthn standartlarının bir ürünüdür. Kullanıcının cihazında güvenli bir şekilde saklanan asimetrik anahtar çifti ile çalışır. Sunucu sadece kullanıcının açık anahtarını tutar; özel anahtar cihazdan çıkmaz. Böylece parola sızıntıları, tekrar kullanım ve kimlik avı (phishing) riskleri büyük ölçüde azalır. Ek olarak, platform doğrulayıcıları (iOS/Android/Windows/macOS) ve bulut senkronizasyonu sayesinde kullanıcı deneyimi neredeyse otomatik doldurma kadar kolay hale gelir.

Temel Kavramlar

Relying Party (RP) ID, genellikle uygulamanızın kök etki alanıdır ve WebAuthn işlemlerinin bağlandığı kimliktir. Origin ise protokol, alan adı ve portun birleşimidir; HTTPS zorunludur. Kayıt sırasında attestation, giriş sırasında assertion adı verilen imzalı veriler üretilir. Sunucu bu verileri doğrular, sayaç (signCount) ile tekrar saldırılarını engeller ve açık anahtarı (public key) güvenli şekilde saklar.

Gereksinimler

Üretimde HTTPS zorunludur; geliştirirken localhost istisna olarak desteklenir. Sunucu tarafında bir WebAuthn doğrulama kütüphanesi kullanmanız pratik olacaktır. Veritabanında kullanıcı kimliği ile eşleştirilmiş credentialId, publicKey, signCount, transports ve tercihe göre attestation bilgilerini saklamalısınız. Tarayıcı tarafında WebAuthn API’sini (navigator.credentials) kullanacaksınız.

Adım 1: RP ID ve Origin Doğrulaması

RP ID, example.com gibi kaydedilebilir kök alan adı olmalıdır. Alt alan adlarında çalışan uygulamalar için RP ID’yi kök alan olarak belirlemek, farklı alt alanlarda aynı passkey’i kullanabilmenizi sağlar. Üretimde https://example.com gibi tam bir origin kullanmalı ve yönlendirmelerinizin origin’i değiştirmediğinden emin olmalısınız.

Adım 2: Kayıt (Registration) Akışı

Önce sunucu, benzersiz bir challenge üretir ve istemciye publicKeyCredentialCreationOptions ile gönderir. Bu seçeneklerde rp, user, challenge, pubKeyAlg (örn. ES256), authenticatorSelection (residentKey ve userVerification tercihleri) ve timeout gibi değerler bulunur. İstemci, navigator.credentials.create({ publicKey: options }) çağrısı ile passkey oluşturur. Elde edilen attestation yanıtını sunucuya gönderirsiniz. Sunucu tarafında imza doğrulanır, RP ID hash’i ve origin kontrol edilir, ardından credentialId, publicKey ve signCount veritabanına kaydedilir. Kullanıcı deneyimi için kayıt sırasında en az iki farklı cihazda passkey oluşturmayı önermek, hesabın kurtarılabilirliğini artırır.

Adım 3: Giriş (Authentication) Akışı

Girişte sunucu yeni bir challenge üretir ve publicKeyCredentialRequestOptions ile istemciye gönderir. Eğer keşfedilebilir kimlik bilgileri (discoverable credentials) kullanıyorsanız kullanıcı adı sormadan doğrudan passkey seçimi mümkün olur. İstemci navigator.credentials.get({ publicKey: options }) çağrısı ile assertion üretir. Sunucu imzayı ve sayaç artışını doğrular; signCount beklenenden düşükse anahtarın çoğaltılmış olabileceğine dair alarm üretir. Başarılı doğrulamadan sonra oturum açılır ve standart oturum yönetimi (cookie veya token) uygulanır.

Adım 4: Conditional UI ve Otomatik Doldurma

Uygun tarayıcılarda “conditional UI” ile kullanıcı adı alanında beklerken passkey önerileri gösterilebilir. Bu deneyim için mediation: "conditional" parametresi ve ilgili tarayıcı desteği gerekir. Kullanıcı adı girmeden tek dokunuşla giriş, dönüşüm oranlarını belirgin biçimde artırabilir.

Güvenlik En İyi Uygulamaları

HTTPS her zaman zorunlu olmalıdır. userVerification’ı mümkünse required yaparak biyometrik/PIN doğrulaması isteyin. COSE algoritmalarını ES256 gibi modern seçeneklerle sınırlayın. Timeout değerlerini gerçekçi tutun ve hataları ayrıntılı ama saldırgana ipucu vermeyecek şekilde loglayın. RP ID ve origin uyuşmazlıkları, SecurityError hatalarının en yaygın sebebidir; alan adı, www/alt alan ayrımları ve proxy ayarlarını dikkatle kontrol edin.

Veri Tabanı Tasarımı

Kullanıcı başına birden çok credential saklayın. Her kayıt için credentialId (ikili/BASE64URL), publicKey (COSE/PEM), signCount (tamsayı), transports (usb, nfc, ble, internal), aaguid ve oluşturulma tarihi alanları tutarlı bir şema oluşturur. Silinen veya kaybolan cihazlar için güvenli kaldırma (soft delete) ve denetim kayıtları (audit log) eklemeniz önerilir.

UX İpuçları

Kullanıcıyı bilgilendiren net mikro metinler kullanın: “Cihaz kilidini açın ve dokunun” gibi. Başarısız denemelerde net ama güvenli hata mesajları verin. İlk kayıt sonrasında “Başka bir cihaz ekle” önerisi sunarak kurtarma olasılığını artırın. Passkey’i mevcut parolalı hesaplara ek ikinci faktör olarak başlatıp zamanla parolayı kaldırma stratejisi de uygulanabilir.

Hata Ayıklama ve Yaygın Sorunlar

NotAllowedError genellikle kullanıcı işlemi iptal ettiğinde veya zaman aşımında görülür. SecurityError RP ID/origin uyumsuzluğunu işaret eder. UnknownError donanım doğrulayıcı veya platform politikası sorunlarına işaret edebilir. Windows Hello için cihazda PIN/Biyometri etkin olmalı; mobilde ekran kilidi şarttır.

Sonuç

Passkey (WebAuthn) ile şifresiz giriş, modern web projelerinde güvenliği artırırken sürtünmeyi azaltır. Doğru RP ID, güvenli sunucu doğrulaması, kullanıcı dostu akış ve çok cihazlı strateji ile hem ölçeklenebilir hem de dayanıklı bir kimlik doğrulama katmanı kurabilirsiniz. Bugünden küçük bir pilotla başlayıp kullanıcı geri bildirimlerine göre geliştirmek, geçiş maliyetini düşürmenin en verimli yoludur.

17 Kasım 2025 Pazartesi

Next.js ile Passkey (WebAuthn) Entegrasyonu: Adım Adım Parolasız Giriş Rehberi

Giriş

Parolasız giriş, kullanıcı deneyimini iyileştirirken güvenlik risklerini ciddi şekilde azaltan modern bir yaklaşım. Passkey teknolojisi, FIDO2/WebAuthn standartları üzerine kurulu olup, kimlik doğrulamayı biyometri (Face ID, Touch ID, Windows Hello) veya cihaz PIN’i gibi yerel yöntemlere devrediyor. Bu rehberde, Next.js tabanlı bir projeye Passkey (WebAuthn) eklemenin pratik bir yolunu adım adım anlatıyorum. Amacımız, hızlıca çalışan bir kayıt (registration) ve giriş (authentication) akışı kurmak.

Neden Passkey?

Parola sızıntıları, kimlik avı (phishing) ve zayıf şifreler artık klasik güvenlik açıkları. Passkey, özel anahtarın cihazda güvenli biçimde saklanması ve sitenizin alan adına (RP ID) bağlanması nedeniyle phishing’e karşı dayanıklıdır. Kullanıcılar şifre hatırlamak zorunda kalmaz; cihazlarının biyometrik sensörleri ile tek dokunuşta oturum açabilirler.

Ön Koşullar

- Next.js 13+ (App Router önerilir), Node.js 18+
- HTTPS ortamı (yerelde localhost istisnası)
- Modern bir tarayıcı (Chrome, Edge, Safari, Firefox; mobil platformlarda da destek artıyor)
- Temel bir veritabanı (PostgreSQL, MySQL veya Prisma ile soyutlama)

Gerekli Paketler

WebAuthn işlemlerini kolaylaştırmak için yaygın olarak kullanılan @simplewebauthn paketlerini kullanacağız. Terminalde aşağıdaki komutu çalıştırın:

npm i @simplewebauthn/server @simplewebauthn/browser zod

Mimariyi Anlamak

Kayıt akışında sunucu, kullanıcı için bir “challenge” üretir ve istemci bu challenge’ı cihazdaki güvenlik anahtarında imzalayıp geri gönderir. Sunucu, gelen yanıtı doğrular ve kimlik bilgilerini (credential) veritabanına yazar. Giriş akışı benzer şekilde çalışır ancak var olan credential ile imzalama yapılır. Tüm süreçte origin (https://alanadiniz.com) ve RP ID (alanadiniz.com) uyumu kritik önemdedir.

Adım 1: Kayıt (Registration) API’si

App Router kullandığınızı varsayalım. Kayıt başlatma için “/api/webauthn/register/options” ve doğrulama için “/api/webauthn/register/verify” uç noktaları oluşturalım.

// app/api/webauthn/register/options/route.ts
import { NextResponse } from 'next/server';
import { generateRegistrationOptions } from '@simplewebauthn/server';

export async function POST() {
  const rpName = 'Uygulama Adı';
  const rpID = process.env.RP_ID || 'localhost'; // üretimde alanadiniz.com
  const user = { id: 'user-123', name: '[email protected]', displayName: 'Ali' };

  const options = await generateRegistrationOptions({
    rpName,
    rpID,
    userID: user.id,
    userName: user.name,
    timeout: 60000,
    attestationType: 'none',
    authenticatorSelection: {
      residentKey: 'preferred',
      userVerification: 'preferred',
    },
  });

  // challenge'ı oturum/cookie/cache'te saklayın
  // ör: await saveChallenge(user.id, options.challenge)

  return NextResponse.json(options);
}

Kullanıcı, tarayıcıda bu seçeneklerle passkey kaydı başlatır. Ardından istemciden dönen yanıtı doğrulamak için verify uç noktası:

// app/api/webauthn/register/verify/route.ts
import { NextResponse } from 'next/server';
import {
  verifyRegistrationResponse,
} from '@simplewebauthn/server';

export async function POST(req: Request) {
  const body = await req.json();
  const rpID = process.env.RP_ID || 'localhost';
  const expectedOrigin = process.env.EXPECTED_ORIGIN || 'http://localhost:3000';

  // const expectedChallenge = await getChallenge(userId)

  const verification = await verifyRegistrationResponse({
    response: body,
    expectedChallenge: '...challenge...',
    expectedOrigin,
    expectedRPID: rpID,
  });

  const { verified, registrationInfo } = verification;

  if (verified && registrationInfo) {
    const {
      credentialPublicKey,
      credentialID,
      counter,
      credentialBackedUp,
      credentialDeviceType,
    } = registrationInfo;

    // Veritabanına kaydedin:
    // credentialID (base64url), publicKey (Buffer), counter, userId vb.

    return NextResponse.json({ ok: true });
  }

  return NextResponse.json({ ok: false }, { status: 400 });
}

Adım 2: İstemci (Kayıt)

İstemci tarafında @simplewebauthn/browser paketini kullanın. Aşağıda basit bir örnek var:

import {
  startRegistration,
} from '@simplewebauthn/browser';

async function registerPasskey() {
  const optionsRes = await fetch('/api/webauthn/register/options', { method: 'POST' });
  const options = await optionsRes.json();

  const attResp = await startRegistration(options);
  const verifyRes = await fetch('/api/webauthn/register/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(attResp),
  });

  if (verifyRes.ok) {
    alert('Passkey kaydedildi!');
  }
}

Adım 3: Giriş (Authentication) API’si

Girişte de benzer iki uç nokta gerekir: “/api/webauthn/auth/options” ve “/api/webauthn/auth/verify”.

// app/api/webauthn/auth/options/route.ts
import { NextResponse } from 'next/server';
import { generateAuthenticationOptions } from '@simplewebauthn/server';

export async function POST() {
  const rpID = process.env.RP_ID || 'localhost';
  // kullanıcıyı e-posta ile tespit ettiğinizi varsayın ve onun credentialID'lerini çekin
  // const allowCredentials = [...] // veritabanından
  const options = await generateAuthenticationOptions({
    rpID,
    timeout: 60000,
    userVerification: 'preferred',
    // allowCredentials,
  });

  // challenge saklanır: await saveAuthChallenge(userId, options.challenge)
  return NextResponse.json(options);
}
// app/api/webauthn/auth/verify/route.ts
import { NextResponse } from 'next/server';
import { verifyAuthenticationResponse } from '@simplewebauthn/server';

export async function POST(req: Request) {
  const body = await req.json();
  const rpID = process.env.RP_ID || 'localhost';
  const expectedOrigin = process.env.EXPECTED_ORIGIN || 'http://localhost:3000';

  // const expectedChallenge = await getAuthChallenge(userId)
  // const authenticator = await getAuthenticator(credentialID)

  const verification = await verifyAuthenticationResponse({
    response: body,
    expectedChallenge: '...challenge...',
    expectedOrigin,
    expectedRPID: rpID,
    authenticator: {
      credentialPublicKey: Buffer.from('...'),
      credentialID: Buffer.from('...'),
      counter: 0,
      transports: ['internal', 'hybrid'],
    },
  });

  const { verified, authenticationInfo } = verification;

  if (verified && authenticationInfo) {
    const { newCounter } = authenticationInfo;
    // counter'ı güncelleyin ve oturum açın (JWT/Session)
    return NextResponse.json({ ok: true });
  }

  return NextResponse.json({ ok: false }, { status: 401 });
}

Adım 4: İstemci (Giriş)

İstemci tarafında startAuthentication ile challenge’ı imzalatıp doğrulamaya gönderin.

import {
  startAuthentication,
} from '@simplewebauthn/browser';

async function loginWithPasskey() {
  const optionsRes = await fetch('/api/webauthn/auth/options', { method: 'POST' });
  const options = await optionsRes.json();

  const asseResp = await startAuthentication(options);
  const verifyRes = await fetch('/api/webauthn/auth/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(asseResp),
  });

  if (verifyRes.ok) {
    // yönlendirme veya token işlemleri
  }
}

Veritabanı ve Güvenlik Notları

- RP ID üretimde çıplak alan adınız olmalı (ör. alanadiniz.com). Subdomain kullanıyorsanız buna dikkat edin.
- expectedOrigin tam şema ile eşleşmeli (https://alanadiniz.com). HTTP yerine HTTPS zorunludur (localhost hariç).
- Veritabanında şu alanlar saklanır: userId, credentialID (base64url), credentialPublicKey (Buffer), counter, transports, deviceType/backup bilgisi.
- Aynı kullanıcı için birden fazla credential destekleyin; kullanıcı yeni cihaz ekleyebilir.
- 0-RTT veya platform senkronizasyonu (iCloud Anahtar Zinciri, Google Password Manager) sayesinde cihazlar arası passkey geçişi mümkün hale gelir.

Sorun Giderme

- NotAllowedError: Genellikle origin veya user gesture eksikliği. Butona tıklama gibi bir kullanıcı etkileşimiyle çağırın.
- SecurityError: RP ID ile origin uyuşmuyor. Ortam değişkenlerini (RP_ID, EXPECTED_ORIGIN) kontrol edin.
- Unknown or unsupported transport: Esnek olun; transports alanını istemci döndürdüğü şekilde saklayın.
- Gömülü tarayıcılar: Bazı uygulama içi web görünümleri WebAuthn’ı kısıtlayabilir; harici tarayıcı önerin.

Sonuç

Passkey ile parolasız giriş, hem kullanıcılar hem de geliştiriciler için büyük bir kazanım. Next.js ve @simplewebauthn ile birkaç uç nokta ve doğru yapılandırma sayesinde modern, phishing’e dayanıklı ve hızlı bir kimlik doğrulama deneyimi sunabilirsiniz. Üretime geçmeden önce HTTPS, alan adı uyumu ve veritabanı bütünlüğü konularını titizlikle test etmeyi unutmayın.

1 Kasım 2025 Cumartesi

Passkey (WebAuthn) ile Parolasız Giriş Nasıl Eklenir? Next.js ve SimpleWebAuthn ile Adım Adım

Passkey nedir ve neden şimdi?

Parolalar artık güvenliğin en zayıf halkası. Passkey, FIDO2 ve WebAuthn standartları ile çalışan, kimlik doğrulamayı cihazınızdaki güvenli donanım modüllerine (Secure Enclave, TPM) emanet eden parolasız bir giriş yöntemidir. Kimlik avına dayanıklıdır, şifre sızmalarından etkilenmez ve iCloud Anahtar Zinciri, Google Parola Yöneticisi ve Microsoft hesabı ile senkronize olabilir. Bu yazıda, modern bir React çerçevesi olan Next.js üzerinde SimpleWebAuthn kullanarak passkey entegrasyonunu adım adım kuracağız.

Mimariyi hızlıca anlayalım

WebAuthn iki temel akıştan oluşur: Kayıt (Registration) ve Giriş (Authentication). Sunucu “relying party” olarak bir challenge üretir, tarayıcı ve cihazınızdaki kimlik doğrulama modülü bu challenge’ı özel anahtar ile imzalar, sunucu da daha önce kaydedilen genel anahtar ile imzayı doğrular. Kritik parametreler: rpId (alan adınız), origin (https kökeniniz), user.id (kalıcı benzersiz kimlik), counter (replay saldırılarına karşı sayaç) ve userVerification (biyometrik/PIN doğrulaması). Hepsi doğru ayarlanmadığında tarayıcı güvenlik nedeniyle işlemi reddeder.

Gerekenler ve kurulum

Başlamak için Node.js 18+ ve Next.js 13+ önerilir. Örneklerde App Router kullanılacaktır. Projeyi oluşturmak için: npx create-next-app@latest passkey-demo. Ardından gerekli kütüphaneler: npm i @simplewebauthn/server @simplewebauthn/browser cookie. Basitlik için oturumları cookie ile yöneteceğiz; gerçek projede JWT veya session store tercih edebilirsiniz.

Kayıt (registration) akışı

1) Sunucu tarafı seçenek üretimi: Kullanıcı yeni bir passkey oluşturmak istediğinde generateRegistrationOptions ile istemciye seçenek döndürün. Örnek ayarlar: rpName: 'Örnek Uygulama', rpID: 'alanadiniz.com', userID: 'kalici-uuid', userName: '[email protected]', attestationType: 'none', authenticatorSelection: { residentKey: 'preferred', userVerification: 'preferred' }. Bu adımda kullanıcıya bir challenge ve uyumlu parametreler verilir.

2) İstemci tarafı oluşturma: Tarayıcıda startRegistration(options) çağrılır ve kullanıcı cihazındaki biyometrik/PIN doğrulaması tetiklenir. İşlem başarılıysa dönen attestationResponse’ı backend’e gönderirsiniz.

3) Doğrulama ve kaydetme: Sunucuda verifyRegistrationResponse ile origin ve rpID doğrulanır. Başarılıysa veritabanına şu alanları kaydedin: credentialId (Base64URL), publicKey, counter, userId, transports, tercihen aaguid ve device type. Bu kayıt, o kullanıcının passkey’inin “kamu anahtarını” temsil eder.

Giriş (authentication) akışı

1) Seçenek üretimi: generateAuthenticationOptions ile istemciye yeni bir challenge gönderin. Eğer sadece belirli kayıtlı kimlik bilgilerine izin vermek isterseniz allowCredentials içinde credentialId’leri gönderin. Parolasız deneyim için discoverable credentials (residentKey) tercih edilir.

2) İstemci doğrulaması: Tarayıcıda startAuthentication(options) çağrılır. Kullanıcı biyometrik/PIN ile onaylar, ortaya çıkan assertionResponse sunucuya gönderilir.

3) Sunucu doğrulaması: verifyAuthenticationResponse ile imza doğrulanır; challenge, origin, rpId ve counter kontrol edilir. Sayaç değeri yükseldiyse veritabanındaki counter güncellenir. Başarılıysa kullanıcıyı oturum açmış sayıp güvenli bir Set-Cookie ile session başlatın.

Üretim için kritik güvenlik ayarları

- HTTPS zorunludur. WebAuthn yalnızca güvenli kökenlerde çalışır (localhost hariç). Cloudflare, Vercel veya kendi Nginx ters proxy’nizle TLS sağlayın.

- rpID tam alan adınız olmalı ve origin ile uyumlu olmalı. Örn. app.ornek.com kullanıyorsanız http:// değil https://app.ornek.com üzerinden test edin.

- userVerification’ı en az preferred, kritik işlemlerde required yapın; böylece biyometri/PIN doğrulaması zorunlu olur.

- Attestation çoğu senaryoda none kalabilir. Cihaz sınıfı kontrolü istiyorsanız indirect veya direct kullanabilir, gizlilik etkilerini değerlendirmelisiniz.

- Orta katmanda rate limiting, CSRF koruması ve replay önlemleri (tek kullanımlık challenge, kısa süreli TTL) uygulayın.

Tarayıcı ve cihaz uyumluluğu

Güncel Chrome, Safari ve Edge sürümleri passkey’i destekliyor. iOS ve Android cihazlarda platform authenticator ile sorunsuz çalışır. Masaüstünde “telefonla doğrula” akışı (QR/BT) mümkün. Kullanıcılara “fiziksel güvenlik anahtarı” (YubiKey) ile ek kayıt yaptırmak da kurtarma planı olarak önerilir.

Sık karşılaşılan hatalar

NotAllowedError: Kullanıcı etkileşimi (click) yoksa veya işlem zaman aşımına uğradıysa görülür. İşlemleri buton tıklamasıyla başlatın ve timeout değerini 60–120 sn yapın.

InvalidStateError: Aynı cihazda aynı kullanıcı için tekrar kayıt deneniyorsa oluşabilir. Kayıt öncesi kullanıcıya mevcut passkey’i kaldırma veya yeni cihaz olarak ekleme seçenekleri sunun.

RP ID hatası: “The RP ID is not a registrable domain” mesajı alıyorsanız muhtemelen localhost dışı http kullanıyorsunuzdur. Her zaman https kullanın ve alan adınızın kökeni ile rpID’yi eşleştirin.

Sonuç ve öneriler

Passkey entegrasyonu hem güvenliği hem de dönüşümü artırır: kullanıcılar parolaları hatırlamak zorunda kalmaz, giriş süresi kısalır. Next.js ve SimpleWebAuthn ikilisiyle temel kurulum birkaç saat içinde tamamlanabilir. Üretimde çoklu cihaz desteği, kurtarma seçenekleri (ikinci passkey, e-posta destekli destek süreci), denetim kayıtları ve ayrıntılı telemetriyi (başarı/başarısızlık oranları, tarayıcı/cihaz dağılımı) planlayın. Parolasız geleceğe adım atmak için bugün küçük bir pilotla başlayabilir, kullanıcılarınızdan gelen geri bildirimlere göre akışı iyileştirebilirsiniz.

9 Ekim 2025 Perşembe

Passkey (FIDO2/WebAuthn) ile Parolasız Giriş: Modern Web Uygulamalarına Adım Adım Entegrasyon

Passkey ve WebAuthn Nedir, Neden Önemli?

Parolasız kimlik doğrulama, güvenlik ve kullanıcı deneyimi açısından modern webin en kritik dönüşümlerinden biri. Passkey teknolojisi, FIDO2 ve WebAuthn standartlarına dayanarak şifreleri tamamen ortadan kaldırır ve herkese açık anahtar kriptografisiyle phishing saldırılarını kökten azaltır. Kullanıcılar, platformlarının (iOS, Android, Windows, macOS) yerleşik güvenlik donanımını veya güvenlik anahtarlarını (YubiKey gibi) kullanarak tek dokunuşla giriş yapar. Bu makalede, bir web uygulamasına passkey (WebAuthn) entegrasyonunu adım adım, pratik ipuçlarıyla anlatıyorum.

WebAuthn Nasıl Çalışır? (Kısa Teknik Özet)

WebAuthn, tarayıcı üzerinden navigator.credentials API’si ile çalışır. Kayıt (registration) aşamasında sunucu bir challenge üretir ve tarayıcıya gönderir. Kullanıcının cihazı benzersiz bir anahtar çifti (özel/public) oluşturur; public key sunucuya kaydedilir. Giriş (authentication) aşamasında sunucu yine bir challenge yollar; cihaz, özel anahtarla bu challenge’ı imzalar ve tarayıcı imzayı sunucuya iletir. Sunucu public key ile imzayı doğruladığında kullanıcı giriş yapar. Şifre yoktur; dolayısıyla credential stuffing ve klasik phishing riskleri dramatik biçimde azalır.

Ön Koşullar ve Mimarinin Temelleri

Entegrasyon için HTTPS zorunludur; rpId (Relying Party ID) genellikle alan adınızın eTLD+1 biçimidir (örneğin example.com). Backend tarafında kayıt ve giriş için iki uç nokta gerekir: /webauthn/register ve /webauthn/login (veya benzer adlar). Bu uç noktalar challenge üretir, tarayıcıdan dönen yanıtları doğrular ve kimlik bilgilerini (credentialId, publicKey, aaguid vb.) saklar. Sunucu tarafında dilinize göre bir WebAuthn/FIDO2 kütüphanesi kullanmanız önerilir; örneğin Node.js için SimpleWebAuthn, .NET için Fido2NetLib, Go için popüler WebAuthn paketleri mevcuttur.

Adım 1: Kayıt (Registration) Akışı

1) Sunucu, kullanıcı hesabı oluşturulurken bir kayıt challenge’ı üretir ve tarayıcıya dönüş yapar. Dönen JSON içinde publicKey alanı olmalıdır (rp, user, challenge, pubKeyCredParams gibi).

2) Tarayıcı tarafında kayıt isteği şu şekilde tetiklenir: const cred = await navigator.credentials.create({ publicKey: options });. Buradaki options, sunucunun verdiği PublicKeyCredentialCreationOptions içeriğidir.

3) Dönen credential, id, rawId, response.attestationObject ve response.clientDataJSON içerir. Bu verileri JSON’a uygun biçimde base64url kodlayıp sunucuya gönderin: POST /webauthn/register/verify.

4) Sunucu, attestation politikasına (genellikle attestation: "none") göre doğrulama yapar, public key ve credentialId’yi kullanıcıyla eşleştirip veritabanına kaydeder. COSE algoritması olarak ES256 varsayılan ve yaygın bir tercihtir.

Adım 2: Giriş (Authentication) ve Passkey Deneyimi

1) Giriş aşamasında sunucu bir doğrulama challenge’ı üretir ve tarayıcıya yollar. Eğer discoverable credentials (kullanıcı adı girmeden hesap seçimi yapılabilen passkey’ler) destekliyorsanız, allowCredentials alanını boş bırakabilirsiniz.

2) Tarayıcı, aşağıdaki çağrıyla kullanıcıdan biyometrik/doğrulama isteği alır: const assertion = await navigator.credentials.get({ publicKey: requestOptions });. Modern tarayıcı ve platformlarda, mediation: "conditional" ile otomatik doldurma benzeri akış sağlayabilirsiniz: navigator.credentials.get({ publicKey: requestOptions, mediation: "conditional" }).

3) Dönen yanıtta response.authenticatorData, response.clientDataJSON ve response.signature bulunur. Bu verileri sunucuya gönderin: POST /webauthn/login/verify. Sunucu, ilgili public key ile imzayı doğrular, signCount değerini günceller ve oturumu başlatır.

En İyi Uygulamalar ve UX İpuçları

Passkey deneyimi, kullanıcı adı ve şifre kutularını tamamen devre dışı bırakabilir. Özellikle Conditional UI desteği ile (Chrome, Android, iOS ve Safari’nin güncel sürümleri) sayfa yüklenir yüklenmez platform, uygun passkey’leri önerir. Kullanıcı tek dokunuşla giriş yapar. Formlarınızda “Passkey ile giriş yap” butonunu net biçimde gösterin; ilk kurulumda parolayı da kabul edip passkey oluşturma adımını teşvik ederek geçişi yumuşatın.

Hesap kurtarma için e-posta doğrulama, yedek güvenlik anahtarları veya müşteri destek süreçleri tasarlayın. Passkey’ler iCloud veya Google hesabı üzerinden cihazlar arasında senkronize olabilir; bu özellik, kullanıcı değişen cihazlarda bile sorunsuz giriş deneyimi sağlar.

Güvenlik ve Uyum Detayları

- HTTPS zorunludur; localhost geliştirme ortamında tarayıcılar özel izinler sunar. Üretimde mutlaka geçerli bir TLS sertifikası kullanın ve TLS 1.2+ desteğini aktif tutun.

- rpId, cookie SameSite ve Secure bayrakları, Origin eşleşmeleri gibi detaylar önemlidir. Ters proxy (Nginx/Caddy/Cloudflare) arkasında header’ların doğru yönlendirildiğinden emin olun.

- Attestation politikanızı iş gereksinimlerine göre belirleyin. Çoğu SaaS için none yeterlidir; regülasyonlu sektörlerde direct veya enterprise gerekebilir.

- Zaman senkronizasyonu (NTP) ve sunucu saat farkı doğrulamada rol oynar; bu nedenle saat kaymasını minimal tutun.

Test, Hata Ayıklama ve Yayına Alma

Geliştirme sırasında tarayıcı konsolunda Security ve Network sekmelerini izleyin; WebAuthn hataları genellikle açıklayıcıdır. localhost üzerinde test ederken rpId olarak “localhost” kullanın. İlk yayında, kademeli açılış (feature flag) ile kullanıcıların küçük bir yüzdesine passkey’i sunup metrikleri takip etmek iyi bir stratejidir: başarı oranı, iptal oranı, geri dönüşler ve destek talepleri ölçülmelidir.

Sonuç: Parolasız Geleceğe Bugünden Geçin

Passkey (FIDO2/WebAuthn) entegrasyonu; daha güvenli, daha hızlı ve daha kullanıcı dostu bir oturum açma deneyimi sağlar. Şifre sıfırlama maliyetlerini düşürür, hesap ele geçirme vakalarını azaltır ve mobil cihazlarda tek dokunuşla giriş imkânı sunar. Bu rehberdeki adımları izleyerek, önce hibrit (parola + passkey) modeliyle başlayabilir, ardından kullanıcılarınız hazır olduğunda tamamen parolasız bir geleceğe geçebilirsiniz.

2 Ekim 2025 Perşembe

Passkey (FIDO2/WebAuthn) ile Şifresiz Giriş: Node.js Üzerinde Adım Adım Kurulum ve En İyi Uygulamalar

Passkey ve WebAuthn Nedir?

Passkey, FIDO2 ve WebAuthn standartları üzerine kurulu, şifre gerektirmeyen modern bir kimlik doğrulama yöntemidir. Kullanıcılar parolayı ezberlemek yerine, cihazlarının biyometrik sensörlerini (parmak izi, yüz tanıma) veya bir ekran kilidini kullanarak giriş yapar. Kriptografik anahtarlar cihazda güvenle saklanır ve çoğu ekosistemde (Apple, Google, Microsoft) bulut üzerinden yedeklenip eşitlenebilir. Bu sayede hem güvenlik artar hem de giriş deneyimi tek dokunuşa iner.

Neden Passkey Kullanmalısınız?

Şifreler kimlik avı, sızan veri setleri ve tekrar kullanım sorunları nedeniyle saldırı yüzeyini genişletir. Passkey ise tarayıcı ve cihaz düzeyinde kimlik bağlamı (origin + rp.id) zorunluluğu ile phishing’e kapıyı kapatır. Ayrıca hızlıdır, kullanıcı memnuniyetini artırır ve destekleyen tarayıcılarda ek yazılım gerektirmeden çalışır. Kısacası güvenlik, hız ve dönüşüm oranı açısından net bir kazanım sağlar.

Mimarinin Özeti

WebAuthn iki ana akıştan oluşur: kayıt (registration/attestation) ve giriş (authentication/assertion). Sunucu benzersiz bir challenge üretir, istemci bunu güvenli donanımda imzalar ve sunucu doğrular. Başarılı kayıt sonunda kullanıcıya ait credentialId, publicKey ve signCount gibi meta veriler veritabanında saklanır. Girişte de benzer şekilde sunucu yeni bir challenge üretir, istemcinin imzasını doğrular ve sayacı günceller.

Gereksinimler ve Hazırlık

- Etki alanınız HTTPS üzerinde çalışmalıdır. Geliştirme için https://localhost istisnai olarak geçerlidir.
- rp.id (relying party id) genellikle alan adınızın eTLD+1 karşılığıdır (ör. example.com). Alt alan adında çalışsanız bile rp.id çoğunlukla kök alan olmalıdır.
- Node.js tarafında popüler kütüphane olarak @simplewebauthn/server ve istemci için @simplewebauthn/browser tercih edebilirsiniz.

Adım Adım Kurulum (Node.js)

Adım 1 – Proje kurulumu: Sunucu için Express veya Fastify kullanabilirsiniz. Temel bağımlılıklar: @simplewebauthn/server, oturum yönetimi için bir middleware ve kalıcı saklama için bir veritabanı (ör. PostgreSQL).

Adım 2 – Kayıt seçeneklerini üretin: /register/generate-options uç noktasında PublicKeyCredentialCreationOptions üretin. rp.name ve rp.id, user.id, user.name, pubKeyCredParams ve authenticatorSelection alanlarını doldurun. authenticatorSelection.userVerification için “required” seçimi güvenliği artırır. Üretilen challenge’ı kullanıcı oturumuna yazın.

Adım 3 – Kayıt doğrulama: İstemci tarafından dönen navigator.credentials.create() sonucu ile /register/verify uç noktasında verifyRegistrationResponse çağrısını yapın. Başarılıysa credentialId, publicKey, counter ve transports bilgilerini veritabanında kullanıcıya bağlayın.

Adım 4 – Giriş seçeneklerini üretin: /login/generate-options uç noktasında PublicKeyCredentialRequestOptions döndürün. allowCredentials alanına kullanıcının kayıtlı credentialId’lerini ekleyin. Tek tık deneyimi için residentKey destekliyorsanız discovery senaryosunu da tasarlayın.

Adım 5 – Giriş doğrulama: İstemcinin navigator.credentials.get() yanıtını /login/verify uç noktasına gönderip verifyAuthenticationResponse ile kontrol edin. İmza geçerliyse oturumu başlatın ve signCount değerini güncelleyin.

İstemci (Tarayıcı) Akışı

Kayıt sırasında sunucudan aldığınız creationOptions ile navigator.credentials.create({ publicKey: creationOptions }) çağrısı yapın. Sonucu sunucuya POST edin. Girişte ise requestOptions ile navigator.credentials.get({ publicKey: requestOptions }) çağrısı yapın. Bu çağrılar kullanıcıyı biyometrik sensör veya cihaz kilidiyle onay vermeye yönlendirir.

Test, Hata Ayıklama ve Uyumluluk

Chrome DevTools’ta “WebAuthn” paneliyle sanal authenticator ekleyebilir, platform ve çapraz platform seçeneklerini simüle edebilirsiniz. Sık karşılaşılan hatalar: NotAllowedError (kullanıcı iptal etti veya zaman aşımı), DOMException: SecurityError (rp.id ve origin uyumsuz), Constraint hataları (ör. residentKey politikası). Üretimde hem platform (telefon, laptop) hem de harici güvenlik anahtarlarını test edin.

Güvenlik ve En İyi Uygulamalar

- Bütünleşik phishing direnci için rp.id ve site origin eşleşmesine dikkat edin.
- Challenge değerini kriptografik olarak güvenli rastgelelik ile üretin ve tek kullanımlık olarak saklayın.
- userVerification’ı “required” kullanmak; başkasının cihazı üzerinden kötüye kullanım riskini azaltır.
- Birden fazla cihaz senkronizasyonunu desteklemek için kullanıcıya birden çok credential eklemeye izin verin.
- Güvenlik anahtarı kaybı için kurtarma akışları (ikinci passkey, e-posta linki, müşteri desteği) tasarlayın.

UX Önerileri

Passkey’i bir opsiyon olarak sunmak yerine “Passkey ile giriş yap” butonunu ön plana alın. Uyumlu tarayıcı ve cihazlarda otomatik doldurma istemini tetiklemek için form alanlarınızı sade tutun. Kayıt sırasında cihaz adını kullanıcıdan alarak (ör. “Mert’in iPhone’u”) hesap ayarlarında listelemeyi kolaylaştırın. Passkey bulunmazsa parolasız alternatif olarak sihirli bağlantı (magic link) sunmak terk oranını düşürür.

Dağıtım ve Aşamalı Geçiş

Mevcut oturum açma sisteminizi bozmadan aşamalı geçiş yapabilirsiniz. Önce kayıtlı kullanıcılarınıza ek kimlik doğrulama metodu olarak passkey tanımlama imkanı verin. Kullanıcı davranışı oturursa parolayı isteğe bağlı hale getirin ve yeni kullanıcılara “passkey-öncelikli” deneyim sunun. CDN veya ters proxy katmanında HTTPS ve HSTS ayarlarının doğru olduğundan emin olun.

Sonuç

Passkey (FIDO2/WebAuthn), şifrelerin yarattığı güvenlik risklerini ve kullanıcı sürtünmesini önemli ölçüde azaltır. Node.js ekosistemindeki olgun kütüphaneler sayesinde entegrasyon birkaç uç noktayı uygulamak kadar basit hale geldi. Doğru rp.id yapılandırması, güvenli challenge yönetimi ve iyi bir UX ile dakikalar içinde modern, phishing dayanıklı ve tek dokunuşla giriş deneyimini hayata geçirebilirsiniz.

19 Eylül 2025 Cuma

Web Uygulamana Passkey (WebAuthn) Ekleme: Node.js ile Şifresiz Giriş Rehberi 2025

Giriş

Şifresiz kimlik doğrulama, son yılların en önemli güvenlik dönüşümlerinden biri. Passkey (FIDO2/WebAuthn) sayesinde kullanıcılar, karmaşık şifrelerle uğraşmadan biyometri, güvenli donanım anahtarları veya cihaz kilidi ile giriş yapabiliyor. Bu rehberde, modern bir web uygulamasına Node.js ve tarayıcı WebAuthn API kullanarak passkey ekleme sürecini adım adım anlatıyorum. Odak noktamız: kolay kurulum, sağlam güvenlik ve güncel tarayıcı desteği.

Ön Koşullar

- Alan adınız ve HTTPS etkin (localhost için https://localhost da çalışır, ancak gerçek kullanıcılar için zorunlu HTTPS gereklidir).
- Node.js 18+ (WebCrypto ve fetch desteği için önerilir).
- Basit bir kullanıcı veritabanı (PostgreSQL, MongoDB ya da SQLite).
- Sunucu tarafında WebAuthn doğrulaması için bir kütüphane (örneğin simplewebauthn).
- RP ID (Relying Party ID) olarak genellikle kök alan adınız: example.com. Origin ise https://app.example.com gibi tam kaynak adresidir.

Mimari ve Akış

WebAuthn iki ana akıştan oluşur: Kayıt (Registration) ve Giriş (Authentication). Her ikisi de sunucunun ürettiği rastgele bir challenge değeriyle başlar.

1) Kayıt: Sunucu kullanıcıyı tanımlar, PublicKeyCredentialCreationOptions oluşturur ve challenge döner. Tarayıcı navigator.credentials.create() ile kullanıcıdan attestation üretir. Sunucu attestation’ı doğrular, credentialId ve publicKey gibi özet bilgileri veritabanına kaydeder.

2) Giriş: Sunucu PublicKeyCredentialRequestOptions döner. Tarayıcı navigator.credentials.get() ile assertion (imzalı kanıt) üretir. Sunucu imzayı ve sayaç değerini doğrular, oturumu açar.

Frontend: Kayıt Akışı

Kullanıcı giriş yaptıktan (veya e-posta doğruladıktan) sonra passkey kaydı başlatın. İstemci tarafında tipik istek:

const regOpts = await fetch('/webauthn/register/options').then(r => r.json());
const credential = await navigator.credentials.create({ publicKey: regOpts });
await fetch('/webauthn/register/verify', { method: 'POST', body: JSON.stringify(credential) });

SEO açısından önemli noktalar: “passkey kaydı”, “WebAuthn tarayıcı API”, “şifresiz kimlik doğrulama” gibi anahtar kelimeleri akışa doğal yerleştirin.

Backend: Kayıt Doğrulama

Sunucuda challenge değerini kullanıcıya özel ve tek kullanımlık olarak üretin. @simplewebauthn/server kullanıyorsanız generateRegistrationOptions ile seçenekleri üretir, verifyRegistrationResponse ile attestation doğrularsınız. Doğrulama sonrası şu alanları saklayın:

- credentialId: Kimlik.
- publicKey: İmza doğrulaması için gereken anahtar.
- signCount: Yeniden oynatma saldırılarına karşı sayaç.
- transports ve aaguid gibi meta bilgiler.

Frontend: Giriş (Authentication) Akışı

Kullanıcı giriş sayfasına geldiğinde, eğer passkey kayıtlıysa “Tek tıkla şifresiz giriş” sunabilirsiniz:

const authOpts = await fetch('/webauthn/auth/options?username=ali').then(r => r.json());
const assertion = await navigator.credentials.get({ publicKey: authOpts });
await fetch('/webauthn/auth/verify', { method: 'POST', body: JSON.stringify(assertion) });

Chrome’un Conditional UI özelliğiyle, kullanıcı adı alanına odaklanıldığında passkey önerisi otomatik çıkar. Bunun için mediation: 'conditional' kullanın ve sayfada autocomplete="username" bulunan bir alan bulundurun.

Güvenlik ve En İyi Uygulamalar

- Origin ve rpId kesin eşleşmeli. Ters proxy (Cloudflare, Nginx) arkası dağıtıma dikkat edin.
- Challenge benzersiz ve kısa ömürlü olsun; kullanıldıktan sonra silin.
- userVerification değerini tehdit modelinize göre belirleyin: required (yüksek güvenlik) veya preferred (daha iyi uyumluluk).
- residentKey (discoverable credentials) ile kullanıcı adı girmeden giriş deneyimi sağlayabilirsiniz. Bunun için residentKey: 'required' ve authenticatorSelection.requireResidentKey = true.
- Çoklu cihaz senkronizasyonu (iCloud Keychain, Google Password Manager) sayesinde passkey’ler cihazlar arasında taşınabilir; ancak kurumsal ortamda donanım güvenlik anahtarlarını (YubiKey vb.) zorunlu kılmak isteyebilirsiniz.

Test ve Hata Ayıklama

Chrome DevTools > More Tools > Virtual Authenticator ile fiziksel cihaz olmadan test yapabilirsiniz. Buradan platform/harici anahtar seçebilir, kullanıcı doğrulamasını simüle edebilirsiniz. Sık görülen hatalar: “Invalid RP ID” (alan adınız uyuşmuyor), “DOMException: The operation is insecure” (HTTPS yok), “Challenge mismatch” (eski veya farklı kullanıcıya ait challenge).

Veri Modeli ve Uyum

Bir kullanıcı birden fazla passkey’e sahip olabilir. Veritabanında users, credentials şeklinde ayrıştırın. Girişte birden çok allowCredentials döndürebilir veya discoverable credential ile boş gönderip tarayıcının seçmesini izleyebilirsiniz. KV veya bellek içi önbellek ile challenge yönetimini hızlandırın. KV kullansanız bile kalıcılık için veritabanına yedekleyin.

Dağıtım İpuçları

Sunucunuz HTTP/2 veya HTTP/3 arkasındaysa, Origin başlığının ve CF-Connecting-IP / X-Forwarded-Proto gibi başlıkların framework’ünüz tarafından doğru işlendiğinden emin olun. Serverless (Vercel, Cloudflare Workers) üzerinde de WebAuthn rahatlıkla çalışır; sadece rpId ve origin sabit ve tutarlı olmalı.

Sonuç

Passkey (WebAuthn) ile şifresiz kimlik doğrulama, hem güvenliği hem kullanıcı deneyimini ciddi biçimde iyileştiriyor. Node.js ve WebAuthn API sayesinde birkaç uç noktayı doğru kurgulayarak dakikalar içinde prototip çıkabilir, Conditional UI ile tek dokunuşla giriş deneyimi sunabilirsiniz. Doğru RP ID, benzersiz challenge yönetimi ve kapsamlı doğrulama kontrolleriyle, 2025’in güvenlik standartlarına uygun modern bir “şifresiz giriş” altyapısını bugün projelerinize ekleyin.

11 Eylül 2025 Perşembe

Passkey (WebAuthn) ile Şifresiz Giriş: Node.js Üzerinden Adım Adım Kurulum ve İpuçları

Passkey (WebAuthn) nedir? Neden şimdi?

Passkey, FIDO2 ve WebAuthn standartlarını temel alan, phishing’e dayanıklı ve kullanıcı dostu bir şifresiz kimlik doğrulama yöntemidir. Tarayıcılar ve işletim sistemleri 2024 itibarıyla passkey’leri yerel olarak destekler hale geldi; 2025’te ise iCloud Anahtar Zinciri, Google Password Manager ve üçüncü parti yöneticiler ile çok cihazlı senkronizasyon yaygınlaştı. Sonuç: Kullanıcılar tek dokunuşla (parmak izi, Face ID, Windows Hello) giriş yapabiliyor, geliştiriciler ise veri ihlallerine açık parola depolama yükünden kurtuluyor.

SEO açısından bakarsak, “şifresiz giriş”, “WebAuthn”, “FIDO2” ve “passkey” gibi terimler özellikle güvenlik ve kullanıcı deneyimi odaklı aramalarda öne çıkıyor. Bu rehberde Node.js ile sıfırdan bir passkey akışını nasıl kurabileceğinizi, istemci ve sunucu tarafındaki kritik ayarları ve üretim ortamında karşılaşabileceğiniz hataları ele alacağım.

Temel mimari ve akış

Kayıt (Registration): Sunucu bir “challenge” üretir, istemci WebAuthn API üzerinden biyometrik/PIN ile bir anahtar çifti oluşturur ve attestation ile sunucuya döner. Sunucu bu veriyi doğrulayıp kullanıcının public key’ini kalıcı olarak kaydeder.

Giriş (Authentication): Sunucu yine bir challenge üretir, istemci kayıtlı credential’ı kullanarak imza (assertion) üretir ve döndürür. Sunucu imzayı public key ile doğrular; eşleşirse oturum açılır.

Hazırlık: Alan, HTTPS ve kütüphaneler

WebAuthn üretimde yalnızca HTTPS üzerinde çalışır (localhost hariç). Relying Party ID (rpId), tarayıcının algıladığı etkin alanla uyuşmalıdır. Örneğin site adresiniz “app.ornek.com” ise rpId “ornek.com” ya da “app.ornek.com” olabilir. Node.js tarafında @simplewebauthn/server veya fido2-lib gibi kütüphaneler doğrulama işini büyük ölçüde kolaylaştırır.

Node.js ile uçtan uca akış (özet)

1) Kayıt için challenge üretin: Kullanıcının henüz passkey’i yoksa sunucu tarafında bir kayıt endpoint’i (ör. /webauthn/registration/options) oluşturun. rp.name, rp.id, user.id (rastgele GUID), user.name ve authenticatorSelection (residentKey: “preferred” veya “required”, userVerification: “preferred”) gibi alanları belirleyin. Challenge’ı sunucu oturumunda saklayın.

2) İstemci tarafında create() çağırın: Tarayıcıda navigator.credentials.create({ publicKey: options }) ile kullanıcıdan biyometrik/PIN onayı alın. Dönüşte attestationObject ve clientDataJSON gelecektir. Bu verileri JSON olarak sunucuya gönderin.

3) Attestation doğrulaması: Sunucuda gelen attestation verisini kütüphaneyle doğrulayın. Başarılıysa credentialId, publicKey (COSE veya JWK), signCount ve AAGUID gibi alanları kullanıcıya bağlı olarak veritabanına kaydedin. Aynı kullanıcıya birden fazla credential tanımlanabilir.

4) Giriş için challenge üretin: /webauthn/authentication/options ile kayıtlı credentialId’leri referans alarak yeni bir challenge üretin. userVerification: “preferred” veya “required” ile MFA benzeri güvenlik seviyesi sağlayabilirsiniz.

5) İstemci tarafında get() çağırın: navigator.credentials.get({ publicKey: requestOptions }) ile kullanıcıdan onay alın. Dönüşte authenticatorData, signature ve clientDataJSON gelir; sunucuya gönderin.

6) Assertion doğrulaması ve oturum: İmza doğrulanırsa oturumu başlatın. JWT veya HttpOnly, Secure, SameSite=strict bir çerezle oturumu yönetin. Replay saldırılarını önlemek için challenge tek kullanımlık olmalı ve kısa süreli (örn. 60 sn) geçerli tutulmalıdır.

Veri modeli: Ne saklamalı?

- Kullanıcı: userId (UUID), email/username, oluşturulma tarihi.

- Credential: userId, credentialId (base64url), publicKey (COSE/JWK), signCount, transports (usb, nfc, ble, internal), aaguid, createdAt.

- Güvenlik: Her doğrulamada signCount karşılaştırması yaparak kopyalanmış authenticator tespitine yardımcı olun (bazı platformlarda sabit kalabilir; kütüphanenin notlarını okuyun).

Üretim ipuçları (Güvenlik ve UX)

- Tam HTTPS: Şifreli bağlantı zorunludur. HSTS etkinleştirilebilir.

- Origin ve rpId uyumu: Hata mesajlarının çoğu burada çıkar. Subdomain değişikliklerinde dikkatli olun.

- Discoverable credentials: Kullanıcı adı öncesi doğrudan passkey ile giriş için residentKey’i “required” yapabilirsiniz. Bu, “şifresiz ve kullanıcı adısız” akış sağlar.

- Conditional UI (Chrome/Safari): Giriş formunuzda kullanıcı adı alanı göstermeden passkey istemek için conditional UI kullanın; özellikle mobilde dönüşüm oranını artırır.

- Oturum yönetimi: HttpOnly + Secure çerez kullanın, SameSite=strict iyidir. Token tabanlı sistemlerde kısa ömürlü access token ve yenileyici mekanizma kurun.

- FallBack ve hesap kurtarma: Yedek kodlar, e-posta linki veya TOTP gibi alternatifleri dengeli biçimde sunun. Amaç passkey’e öncelik verip erişilebilirliği korumaktır.

- Attestation politikası: Çoğu tüketici uygulaması “none” kullanır. Kurumsal gereksinimlerde belirli üreticilere kısıtlama getirmek için attestation “direct” değerlendirilebilir.

- Rate limit ve anti-automation: Kayıt ve giriş uç noktalarınızı hız sınırlayın, bot koruması ekleyin.

Sık karşılaşılan hatalar ve çözümleri

“The relying party ID is not a registrable domain suffix...” rpId alan adınızla uyuşmuyor olabilir. Geliştirmede localhost kullanın; üretimde tam alan adıyla test edin.

“NotAllowedError” Kullanıcı işlemi iptal etmiş olabilir veya conditional UI tetiklenmemiştir. get()/create() çağrısını kullanıcı etkileşimi (click) bağlamında başlatın.

Attestation doğrulama başarısız Sertifika zinciri veya format hatası olabilir. @simplewebauthn gibi kütüphanelerin güncel sürümünü kullanın; ham binary verileri doğru base64url kodladığınızdan emin olun.

Safari farklılıkları iOS’ta üçüncü parti iframe içinde WebAuthn kısıtlı olabilir. Mümkünse üst alan üzerinde akışı çalıştırın.

Sonuç

Passkey (WebAuthn) ile şifresiz giriş, güvenliği artırırken kullanıcı deneyimini sadeleştirir. Node.js tarafında doğru rpId/origin ayarları, tek kullanımlık challenge’lar, güvenli oturum yönetimi ve iyi bir veri modeli ile üretim seviyesinde sağlam bir akış kurabilirsiniz. 2025 itibarıyla tarayıcı ve işletim sistemi desteği olgunlaştığı için, yeni projelerde parolayı varsayılan kabul etmek yerine passkey’i birincil kimlik doğrulama olarak düşünmek artık pratik ve rekabetçidir. Küçük başlayın, conditional UI ile sürtünmeyi azaltın ve kademeli geçiş stratejisiyle mevcut kullanıcı tabanınızı passkey’e taşıyın.

3.

10 Eylül 2025 Çarşamba

Passkey (FIDO2/WebAuthn) ile Parolasız Giriş: Adım Adım Kurulum ve En İyi Uygulamalar

Passkey nedir ve neden şimdi?

Şifreler tarihsel olarak en zayıf halkaydı: yeniden kullanım, kimlik avı, veri sızıntıları ve karmaşa. Passkey, FIDO2 ve WebAuthn standartlarını temel alarak parolayı tamamen devreden çıkarır. Kullanıcı, cihazındaki biyometrik sensör (Face ID, Touch ID, Windows Hello) veya donanımsal güvenlik anahtarıyla (YubiKey vb.) kimlik doğrular; site ise yalnızca herkese açık anahtarı saklar. Bu yaklaşım, kimlik avına dayanıklı, hızlı ve kullanıcı dostu bir deneyim sunar.

Mimari: Nasıl çalışır?

Passkey, tarayıcı ve işletim sistemi ile cihazdaki “Authenticator” (platform ya da harici) arasında köprü kuran WebAuthn API’sini kullanır. Sunucu tarafında “Relying Party” (RP) olarak adlandırılan uygulamanız, kullanıcıyı kaydederken ve oturum açarken kriptografik bir “challenge” üretir. Tarayıcı, navigator.credentials üzerinden bu challenge’ı imzalatır ve sonucu sunucuya gönderir. Sunucu, imzayı doğrular ve kullanıcıyı oturum açmış kabul eder. Bu süreçte parola yoktur; saklanan tek kalıcı bilgi, cihazın herkese açık anahtarı ve kimlikleyici meta verileridir.

Ön koşullar ve gereksinimler

- HTTPS zorunludur. Lokal geliştirme için localhost istisnadır, üretimde sertifikanızın düzgün kurulu olması gerekir.
- Modern tarayıcı desteği (Chrome, Edge, Safari, Firefox) yaygınlaşmıştır; mobil işletim sistemlerinde de yerleşik destek mevcuttur.
- Alan adı ve rpId uyumu: Örneğin uygulamanız auth.example.com’da ise RP ID’nizi example.com veya ilgili alt alan adıyla uyumlu ayarlayın.

Uygulama seçenekleri

1) Sıfırdan uygulama: Sunucu dilinize uygun bir WebAuthn kütüphanesi kullanın. Node.js için @simplewebauthn/server, Go için duo-labs/webauthn, Python için webauthn, Java için webauthn4j gibi olgun projeler mevcuttur. Bu kütüphaneler, challenge üretimi, attestation/assertion doğrulaması ve anahtar formatlarını sizin yerinize yönetir.

2) Kimlik sağlayıcıları: Auth0, Azure AD B2C, Okta, Firebase gibi servisler passkey desteğini hızla entegre etmenizi sağlar. Bu yol, güvenlik ve mevzuat tarafında işleri kolaylaştırırken, özelleştirme esnekliğini sınırlayabilir.

3) CMS ve hazır platformlar: Bazı modern CMS’ler ve e-ticaret eklentileri passkey desteği sunmaya başladı. Kod yazmadan aktivasyon yapmak mümkün olsa da RP ID, yedek yöntemler ve çok cihaz desteği gibi ayarları doğru yapılandırdığınızdan emin olun.

Adım adım temel kurulum

1) Kullanıcı modeli: Veritabanında kullanıcıya kalıcı bir benzersiz tanımlayıcı (user.id) atayın. E-posta/telefon gibi iletişim bilgilerini tutun; kurtarma senaryoları için gerekecektir.

2) Kayıt (registration) başlangıcı: /webauthn/register/options benzeri bir uç nokta üzerinden, kullanıcı için publicKeyCredentialCreationOptions oluşturun. Parametrelerde rpId, challenge (kısa ömürlü, tek kullanımlık), user bilgisi, algoritmalar (ES256 varsayılan), residentKey ve userVerification politikalarını belirleyin.

3) İstemci tarafı kayıt: Tarayıcıda navigator.credentials.create() çağrısı yapılır. Kullanıcı, biyometri veya güvenlik anahtarıyla onay verir. Dönen PublicKeyCredential nesnesini sunucuya gönderirsiniz.

4) Sunucu doğrulaması: Attestation verisini kontrol edin (origin, rpIdHash, challenge eşleşmesi, algoritmalar). Gerekirse attestation’ı “none” kabul ederek gizliliği artırın. Sonuçta credentialId, publicKey ve signCount değerlerini veritabanına kaydedin.

5) Giriş (authentication) başlangıcı: /webauthn/authenticate/options ile publicKeyCredentialRequestOptions üretin. İlgili kullanıcı için kayıtlı kimlikleyicileri gönderin ya da kullanıcı adı olmadan (discoverable credentials) giriş akışını destekleyin.

6) İstemci tarafı giriş: navigator.credentials.get() çağrısıyla imzalanmış assertion elde edilir ve sunucuya gönderilir.

7) Sunucu doğrulaması ve oturum: İmzayı publicKey ile doğrulayın, signCount artışını kontrol edin (geri sarma tespitleri için). Başarılıysa oturum oluşturun veya JWT üretin. Risk tabanlı ek doğrulamalar (cihaz parmak izi, IP, hız limiti) bu aşamada değerlendirilebilir.

UX ve güvenlik için en iyi uygulamalar

- Kullanıcıyı bilgilendirin: “Passkey, cihazınızda güvenle saklanır ve kimlik avına dayanıklıdır” gibi net açıklamalar ekleyin. İlk oturum açmada kısa bir tur (tooltip) deneyimi dönüşümü artırır.

- Çok cihaz desteği: Platform (telefon/laptop) ve harici (NFC/Bluetooth/USB) anahtarlarla kayıt izni verin. Böylece cihaz kaybında erişim riski azalır.

- Kurtarma stratejisi: En az bir yedek yöntem tanımlayın (destek bileti, güvenlik sorularından kaçının; e-posta veya TOTP daha güvenlidir). İş kritik ortamlarda yönetici onayı veya kimlik doğrulama akışıyla destekleyin.

- Gizlilik ve attestation: Çoğu tüketici uygulaması için attestation “none” politikası yeterlidir. Regülasyon gerektiren ortamlarda üretici sertifikalarını doğrulayan bir güven zinciri kullanın.

- RP ID ve alt alan adları: Oturum açma alan adınız ile uygulama alan adınız farklıysa, rpId ayarını yanlış yapılandırmak en yaygın hatalardandır. Tarayıcı hataları “rpId mismatch” olarak döner.

- Performans: Challenge süre sonunu kısa (örn. 60–120 sn) tutun, CDN önbelleğini bu uç noktalardan uzak tutun. Mobil tarayıcıların arka plan kısıtlarına dikkat edin.

Test ve sorun giderme

- Sanal kimlikleyici: Chrome DevTools > More tools > Virtual authenticator environment ile local test yapın; farklı alg, UV politikaları ve resident key senaryolarını simüle edin.

- Uçtan uca test: WebAuthn.io gibi topluluk araçlarıyla doğrulama akışınızı karşılaştırın. Farklı tarayıcı ve platformlarda (iOS, Android, Windows, macOS) gerçek cihaz testleri yapın.

- Yaygın hatalar: NotAllowedError (kullanıcı iptali veya zaman aşımı), InvalidStateError (mevcut credential ile tekrar kayıt), COSE algoritma uyumsuzluğu (ES256 önerilir) ve saat farkları (server/client saat uyuşmazlığı) sık karşılaşılır. Log’larda challenge-id eşleşmesini ve origin değerini mutlaka izleyin.

Sonuç

Passkey, hem güvenlik hem de kullanıcı deneyimi açısından parolaların doğal halefidir. Doğru RP ID yapılandırması, sağlam bir kurtarma stratejisi ve tarayıcılar arası test ile haftalar içinde üretime alınabilir. İster hazır bir kimlik sağlayıcısıyla hızlıca başlayın, ister kendi WebAuthn katmanınızı inşa edin; passkey, kimlik avına dayanıklı, hızlı ve modern bir giriş deneyimini standart hale getirir.