---
url: 'https://www.corbado.com/tr/blog/dijital-kimlik-bilgisi-dogrulayici-nasil-olusturulur'
title: 'Dijital Kimlik Bilgisi Doğrulayıcı Nasıl Oluşturulur (Geliştirici Rehberi)'
description: 'Next.js, OpenID4VP ve ISO mDoc kullanarak sıfırdan bir dijital kimlik bilgisi doğrulayıcı oluşturmayı öğrenin. Bu adım adım geliştirici rehberi, mobil sürücü belgelerini ve diğer dijital kimlik bilgilerini talep edebilen, alabilen ve doğrulayabilen bir do'
lang: 'tr'
author: 'Amine'
date: '2025-08-20T15:39:46.015Z'
lastModified: '2026-03-25T10:08:04.221Z'
keywords: 'dijital kimlik bilgisi doğrulayıcı, doğrulayıcı rehberi, doğrulayıcı oluşturma'
category: 'Digital Credentials'
---

# Dijital Kimlik Bilgisi Doğrulayıcı Nasıl Oluşturulur (Geliştirici Rehberi)

## 1. Giriş

Çevrimiçi kimlikleri kanıtlamak sürekli bir zorluktur ve bu durum şifrelere ve hassas
belgelerin güvenli olmayan kanallar üzerinden paylaşılmasına yol açmaktadır. Bu durum,
işletmeler için kimlik doğrulamasını yavaş, pahalı ve dolandırıcılığa açık bir süreç
haline getirmiştir.
[Dijital Kimlik Bilgileri](https://www.corbado.com/tr/blog/dijital-kimlik-bilgileri-passkeys), kullanıcıları
verilerinin kontrolüne geri koyarak yeni bir yaklaşım sunar. Bunlar, sürücü belgesinden
üniversite diplomasına kadar her şeyi içeren fiziksel bir
[cüzdan](https://www.corbado.com/tr/blog/dijital-cuzdan-guvencesi)ın dijital eşdeğeridir, ancak kriptografik
olarak güvenli, gizliliği koruyan ve anında doğrulanabilir olma gibi ek avantajlara
sahiptir.

Bu rehber, geliştiricilere
[Dijital Kimlik Bilgileri](https://www.corbado.com/tr/blog/dijital-kimlik-bilgileri-passkeys) için bir
doğrulayıcı oluşturmaya yönelik pratik, adım adım bir
[eğitim](https://www.corbado.com/tr/blog/react-express-mysql-crud-uygulamasi) sunmaktadır. Standartlar mevcut
olsa da, bunların nasıl uygulanacağına dair çok az rehberlik bulunmaktadır. Bu
[eğitim](https://www.corbado.com/tr/blog/react-express-mysql-crud-uygulamasi) bu boşluğu doldurarak, tarayıcının
yerel [Dijital Kimlik](https://www.corbado.com/tr/glossary/open-id-4-vp) Bilgisi API'sini, sunum protokolü için
[OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp) ve kimlik bilgisi formatı olarak ISO
[mDoc](https://www.corbado.com/glossary/mdoc) (örneğin [mobil sürücü belgesi](https://www.corbado.com/tr/blog/mobil-surucu-belgesi))
kullanarak bir doğrulayıcının nasıl oluşturulacağını gösterir.

Sonuç, uyumlu bir mobil cüzdandan bir [Dijital Kimlik](https://www.corbado.com/tr/glossary/open-id-4-vp)
Bilgisini talep edebilen, alabilen ve doğrulayabilen basit ama işlevsel bir
[Next.js](https://www.corbado.com/blog/nextjs-passkeys) uygulaması olacaktır.

İşte nihai uygulamanın çalışır haldeki hızlı bir görünümü. Süreç dört ana adımdan oluşur:

**Adım 1: Başlangıç Sayfası** Kullanıcı başlangıç sayfasına gelir ve süreci başlatmak için
"[Dijital Kimlik](https://www.corbado.com/tr/glossary/open-id-4-vp) ile Doğrula"ya tıklar.
![Doğrulama talebi için başlangıç sayfası](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_33_5217b35c96.png)

**Adım 2: Güven Onayı** Tarayıcı kullanıcıdan güven onayı ister. Kullanıcı devam etmek
için "Devam Et"e tıklar.
![Tarayıcı güven onayı](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_39_ba390a8097.png)

**Adım 3: QR Kod Taraması** Kullanıcının uyumlu
[cüzdan](https://www.corbado.com/tr/blog/dijital-cuzdan-guvencesi) uygulamasıyla tarayacağı bir QR kodu
görüntülenir.
![Tarama için QR kodu](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_45_3b30669a10.png)

**Adım 4: Çözümlenmiş Kimlik Bilgisi** Başarılı doğrulamadan sonra, uygulama çözümlenmiş
kimlik bilgisi verilerini görüntüler.
![Çözümlenmiş kimlik bilgisi sonucu](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_01_36_684f7489cd.png)

### 1.1 Nasıl Çalışır?

Dijital kimlik bilgilerinin arkasındaki sihir, üç kilit oyuncuyu içeren basit ama güçlü
bir "**güven üçgeni**" modelinde yatar:

- **Yayıncı (Issuer):** Kriptografik olarak imzalayıp kullanıcıya bir kimlik bilgisi
  düzenleyen güvenilir bir otorite (örneğin, bir [hükümet](https://www.corbado.com/passkeys-for-public-sector)
  kurumu, üniversite veya banka).
- **Sahip (Holder):** Kimlik bilgisini alan ve cihazındaki kişisel bir dijital cüzdanda
  güvenli bir şekilde saklayan kullanıcı.
- **Doğrulayıcı (Verifier):** Kullanıcının kimlik bilgisini kontrol etmesi gereken bir
  uygulama veya hizmet.

![W3C Doğrulanabilir Kimlik Bilgileri Ekosistemi](https://www.w3.org/TR/vc-data-model/diagrams/ecosystem.svg)

Bir kullanıcı bir hizmete erişmek istediğinde,
[cüzdan](https://www.corbado.com/tr/blog/dijital-cuzdan-guvencesi)ından kimlik bilgisini sunar. Doğrulayıcı daha
sonra orijinal yayıncıyla doğrudan iletişime geçmeye gerek kalmadan orijinalliğini anında
kontrol edebilir.

### 1.2 Doğrulayıcılar Neden Önemlidir (ve Neden Buradasınız)?

Bu **merkeziyetsiz kimlik ekosisteminin** gelişmesi için, **doğrulayıcının** rolü
kesinlikle kritiktir. Onlar bu yeni güven
[altyapısının](https://www.corbado.com/passkeys-for-critical-infrastructure) bekçileridir, kimlik bilgilerini
tüketen ve onları gerçek dünyada kullanışlı hale getirenlerdir. Aşağıdaki diyagramda
gösterildiği gibi, bir doğrulayıcı, sahipten bir kimlik bilgisini talep ederek, alarak ve
doğrulayarak güven üçgenini tamamlar.

Eğer bir geliştiriciyseniz, bu doğrulamayı gerçekleştirecek bir hizmet oluşturmak, yeni
nesil güvenli ve kullanıcı merkezli uygulamalar için temel bir beceridir. Bu rehber, sizi
tam olarak bu süreçte yönlendirmek için tasarlanmıştır. İmza doğrulama ve kimlik bilgisi
durumunu kontrol etme gibi temel kavramlardan ve standartlardan adım adım uygulama
detaylarına kadar, **kendi doğrulanabilir kimlik bilgisi doğrulayıcınızı oluşturmak** için
bilmeniz gereken her şeyi ele alacağız.

> **İleri atlamak mı istiyorsunuz?** Bu eğitimin tamamlanmış projesini GitHub'da
> bulabilirsiniz. Klonlayıp kendiniz denemekten çekinmeyin:
> [https://github.com/corbado/digital-credentials-example](https://github.com/corbado/digital-credentials-example)

Haydi başlayalım.

## 2. Bir Doğrulayıcı Oluşturmak İçin Ön Koşullar

Başlamadan önce, şunlara sahip olduğunuzdan emin olun:

1. **Dijital Kimlik Bilgileri ve mdoc Hakkında Temel Bilgi**
    - Bu [eğitim](https://www.corbado.com/tr/blog/react-express-mysql-crud-uygulamasi), **ISO mDoc** formatına
      (örneğin, mobil sürücü belgeleri için) odaklanmaktadır ve W3C Doğrulanabilir Kimlik
      Bilgileri (VC'ler) gibi diğer formatları kapsamamaktadır. [mdoc](https://www.corbado.com/glossary/mdoc)
      temel kavramlarına aşinalık yardımcı olacaktır.
2. **Docker ve Docker Compose**
    - Projemiz, OIDC oturum durumunu yönetmek için bir Docker container'ında
      [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide) veritabanı kullanır. Her ikisinin de
      kurulu ve çalışır durumda olduğundan emin olun.
3. **Seçilen Protokol: OpenID4VP**
    - Kimlik bilgisi değişim akışı için **OpenID4VP** (OpenID for Verifiable
      Presentations) protokolünü kullanacağız.
4. **Teknoloji Yığını Hazır**
    - Arka uç mantığı için **TypeScript** (Node.js) kullanın.
    - Hem arka uç (API rotaları) hem de ön uç (UI) için **Next.js** kullanın.
    - Anahtar kütüphaneler: [mdoc](https://www.corbado.com/glossary/mdoc) ayrıştırması için
      [CBOR](https://www.corbado.com/glossary/cbor) çözme kütüphaneleri ve bir
      [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide) istemcisi.
5. **Test Kimlik Bilgileri ve Cüzdan**
    - [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android) için
      [OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp) taleplerini anlayan ve mdoc kimlik bilgilerini
      sunabilen
      **[CMWallet](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220)**'ı
      kullanacağız.
6. **Temel Kriptografi Bilgisi**
    - mdoc ve OIDC akışlarıyla ilgili olarak dijital imzaları ve açık/özel anahtar
      kavramlarını anlayın.

---

Şimdi bu ön koşulların her birini, bu mdoc tabanlı doğrulayıcının temelini oluşturan
standartlar ve protokollerle başlayarak ayrıntılı olarak ele alacağız.

### 2.1 Protokol Seçimleri

Doğrulayıcımız aşağıdakiler için oluşturulmuştur:

| Standart / Protokol                                                                       | Açıklama                                                                                                                                                                                                                                |
| :---------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[W3C VC](https://www.w3.org/TR/vc-data-model/)**                                        | W3C Doğrulanabilir Kimlik Bilgileri Veri Modeli. Beyanlar, meta veriler ve kanıtlar dahil olmak üzere dijital kimlik bilgileri için standart yapıyı tanımlar.                                                                           |
| **[SD-JWT](https://datatracker.ietf.org/doc/draft-ietf-oauth-selective-disclosure-jwt/)** | JWT'ler için Seçici Açıklama. Sahiplerin bir kimlik bilgisinden yalnızca belirli beyanları seçici olarak açıklamasına olanak tanıyan, gizliliği artıran JSON Web Token'larına dayalı bir VC formatı.                                    |
| **[ISO mDoc](https://www.iso.org/standard/69084.html)**                                   | ISO/IEC 18013-5. Mobil Sürücü Belgeleri (mDL'ler) ve diğer mobil kimlikler için uluslararası standart, çevrimdışı ve çevrimiçi kullanım için veri yapılarını ve iletişim protokollerini tanımlar.                                       |
| **OpenID4VP**                                                                             | Doğrulanabilir Sunumlar için OpenID. OAuth 2.0 üzerine inşa edilmiş, birlikte çalışabilir bir sunum protokolü. Bir doğrulayıcının kimlik bilgilerini nasıl talep ettiğini ve bir sahibinin cüzdanının bunları nasıl sunduğunu tanımlar. |

Bu eğitim için özel olarak şunları kullanıyoruz:

- Kimlik bilgilerini talep etme ve alma protokolü olarak **OpenID4VP**.
- Kimlik bilgisi formatı olarak **ISO mDoc** (örneğin, mobil sürücü belgeleri için).

> **Kapsam Notu:** W3C VC ve SD-JWT'yi daha geniş bir bağlam sağlamak için kısaca
> tanıtmamıza rağmen, bu eğitim yalnızca [OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp) aracılığıyla
> ISO mDoc kimlik bilgilerini uygular. W3C tabanlı VC'ler bu örnek için kapsam dışıdır.

#### 2.1.1 ISO mDoc (Mobil Belge)

ISO/IEC 18013-5 mDoc standardı, mobil sürücü belgeleri (mDL'ler) gibi mobil belgeler için
yapıyı ve kodlamayı tanımlar. mDoc kimlik bilgileri [CBOR](https://www.corbado.com/glossary/cbor) ile kodlanmış,
kriptografik olarak imzalanmış ve doğrulama için dijital olarak sunulabilir.
Doğrulayıcımız bu mdoc kimlik bilgilerini çözmeye ve doğrulamaya odaklanacaktır.

#### 2.1.2 OpenID4VP (Doğrulanabilir Sunumlar için OpenID)

OpenID4VP, [OAuth 2.0](https://www.corbado.com/glossary/oauth2) ve OpenID Connect üzerine inşa edilmiş, dijital
kimlik bilgilerini talep etmek ve sunmak için birlikte çalışabilir bir protokoldür. Bu
uygulamada, OpenID4VP şunlar için kullanılır:

- Kimlik bilgisi sunum akışını başlatma (QR kodu veya tarayıcı API'si aracılığıyla)
- Kullanıcının cüzdanından mdoc kimlik bilgisini alma
- Güvenli, durum bilgisi olan ve gizliliği koruyan kimlik bilgisi alışverişi sağlama

### 2.2 Teknoloji Yığını Seçimleri

Standartları ve protokolleri net bir şekilde anladığımıza göre, doğrulayıcımızı oluşturmak
için doğru teknoloji yığınını seçmemiz gerekiyor. Seçimlerimiz, sağlamlık, geliştirici
deneyimi ve modern web ekosistemiyle uyumluluk için tasarlanmıştır.

#### 2.2.1 Dil: TypeScript

Hem ön uç hem de arka uç kodumuz için **TypeScript** kullanacağız. JavaScript'in bir üst
kümesi olarak, statik tipleme ekler, bu da hataları erken yakalamaya, kod kalitesini
artırmaya ve karmaşık uygulamaları yönetmeyi kolaylaştırmaya yardımcı olur. Kimlik bilgisi
doğrulaması gibi güvenliğe duyarlı bir bağlamda, tür güvenliği büyük bir avantajdır.

#### 2.2.2 Çerçeve: Next.js

**Next.js**, tam yığın uygulamalar oluşturmak için sorunsuz, entegre bir deneyim sağladığı
için tercih ettiğimiz çerçevedir.

- **Ön Uç İçin:** Doğrulama sürecinin başlatıldığı (örneğin, bir QR kodunun
  görüntülendiği) kullanıcı arayüzünü oluşturmak için [React](https://www.corbado.com/blog/react-passkeys) ile
  [Next.js](https://www.corbado.com/blog/nextjs-passkeys) kullanacağız.
- **Arka Uç İçin:** Sunucu tarafı uç noktaları oluşturmak için **Next.js API
  Rotalarından** yararlanacağız. Bu uç noktalar, geçerli OpenID4VP talepleri oluşturmaktan
  ve CMWallet'tan gelen nihai yanıtı güvenli bir şekilde almak ve doğrulamak için
  `redirect_uri` olarak hareket etmekten sorumludur.

#### 2.2.3 Anahtar Kütüphaneler

Uygulamamız, ön uç ve arka uç için belirli bir kütüphane setine dayanmaktadır:

- **next**: Hem arka uç API rotaları hem de ön uç UI için kullanılan
  [Next.js](https://www.corbado.com/blog/nextjs-passkeys) çerçevesi.
- **react** ve **react-dom**: Ön uç kullanıcı arayüzünü güçlendirir.
- **cbor-web**: [CBOR](https://www.corbado.com/glossary/cbor) ile kodlanmış mdoc kimlik bilgilerini
  kullanılabilir JavaScript nesnelerine çözmek için kullanılır.
- **mysql2**: Zorlukları ve doğrulama oturumlarını depolamak için
  [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide) veritabanı bağlantısı sağlar.
- **uuid**: Benzersiz zorluk dizeleri (nonces) oluşturmak için bir kütüphane.
- **@types/uuid**: UUID oluşturma için TypeScript türleri.

> **`openid-client` Üzerine Not:** Daha gelişmiş, üretim düzeyindeki doğrulayıcılar,
> OpenID4VP protokolünü doğrudan arka uçta işlemek için `openid-client` kütüphanesini
> kullanabilir ve dinamik bir `redirect_uri` gibi özellikleri etkinleştirebilir. Bir
> `redirect_uri` ile sunucu odaklı bir OpenID4VP akışında, `openid-client` `vp_token`
> yanıtlarını doğrudan ayrıştırmak ve doğrulamak için kullanılacaktır. Bu eğitim için,
> süreci anlamayı kolaylaştıran, gerektirmeyen daha basit, tarayıcı aracılı bir akış
> kullanıyoruz.

Bu teknoloji yığını, tarayıcının Dijital Kimlik Bilgisi API'sine ve ISO mDoc kimlik
bilgisi formatına odaklanmış, sağlam, tür güvenli ve ölçeklenebilir bir doğrulayıcı
uygulaması sağlar.

### 2.3 Bir Test Cüzdanı ve Kimlik Bilgileri Edinin

Doğrulayıcınızı test etmek için, tarayıcının Dijital Kimlik Bilgisi API'si ile etkileşime
girebilen bir mobil cüzdana ihtiyacınız var.

[Android](https://www.corbado.com/blog/how-to-enable-passkeys-android) için sağlam bir OpenID4VP uyumlu test
cüzdanı olan
**[CMWallet](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220)**'ı
kullanacağız.

**CMWallet Nasıl Kurulur (Android):**

1. Yukarıdaki bağlantıyı kullanarak APK dosyasını doğrudan
   [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android) cihazınıza **indirin**.
2. Cihazınızın **Ayarlar > Güvenlik** bölümünü açın.
3. Dosyayı indirmek için kullandığınız tarayıcı için **"Bilinmeyen uygulamaları yükle"**
   seçeneğini etkinleştirin.
4. İndirilen APK'yı "İndirilenler" klasörünüzde bulun ve kuruluma başlamak için üzerine
   dokunun.
5. Kurulumu tamamlamak için ekrandaki talimatları izleyin.
6. CMWallet'ı açtığınızda, doğrulama akışına hazır test kimlik bilgileriyle önceden
   yüklenmiş olduğunu göreceksiniz.

> **Not:** Yalnızca güvendiğiniz kaynaklardan APK dosyaları yükleyin. Sağlanan bağlantı
> resmi proje deposundandır.

### 2.4 Kriptografi Bilgisi

Uygulamaya dalmadan önce, doğrulanabilir kimlik bilgilerinin temelini oluşturan
kriptografik kavramları anlamak önemlidir. Onları "doğrulanabilir" ve güvenilir kılan
budur.

#### 2.4.1 Dijital İmzalar: Güvenin Temeli

Özünde, bir Doğrulanabilir Kimlik Bilgisi, bir yayıncı tarafından dijital olarak
imzalanmış bir dizi beyandır (ad, doğum tarihi vb. gibi). Bir dijital imza iki kritik
güvence sağlar:

- **Orijinallik:** Kimlik bilgisinin gerçekten yayıncı tarafından oluşturulduğunu ve bir
  sahtekar tarafından oluşturulmadığını kanıtlar.
- **Bütünlük:** Kimlik bilgisinin imzalandığından beri değiştirilmediğini veya tahrif
  edilmediğini kanıtlar.

#### 2.4.2 Açık/Özel Anahtar Kriptografisi

Dijital imzalar, açık/özel anahtar kriptografisi (asimetrik kriptografi olarak da
adlandırılır) kullanılarak oluşturulur. İşte bizim bağlamımızda nasıl çalıştığı:

1. **Yayıncının bir anahtar çifti vardır:** gizli tutulan bir özel anahtar ve herkese açık
   olan bir açık anahtar (genellikle DID Belgesi aracılığıyla).
2. **İmzalama:** Bir yayıncı bir kimlik bilgisi oluşturduğunda, o belirli kimlik bilgisi
   verileri için benzersiz bir dijital imza oluşturmak üzere **özel anahtarını** kullanır.
3. **Doğrulama:** Doğrulayıcımız kimlik bilgisini aldığında, imzayı kontrol etmek için
   yayıncının **açık anahtarını** kullanır. Kontrol geçerse, doğrulayıcı kimlik bilgisinin
   orijinal olduğunu ve tahrif edilmediğini bilir. Kimlik bilgisi verilerindeki herhangi
   bir değişiklik imzayı geçersiz kılar.

> **DID'ler Üzerine Not:** Bu eğitimde, yayıncı anahtarlarını DID'ler aracılığıyla
> çözümlemiyoruz. Üretimde, yayıncılar genellikle açık anahtarları DID'ler veya diğer
> yetkili uç noktalar aracılığıyla sunar ve doğrulayıcı bunları kriptografik doğrulama
> için kullanır.

#### 2.4.3 JWT Olarak Doğrulanabilir Kimlik Bilgileri

Doğrulanabilir Kimlik Bilgileri genellikle **JSON Web Token'ları (JWT'ler)** olarak
biçimlendirilir. Bir JWT, iki taraf arasında aktarılacak beyanları temsil etmenin kompakt,
URL-güvenli bir yoludur. İmzalı bir JWT'nin (JWS olarak da bilinir) noktalarla (`.`)
ayrılmış üç bölümü vardır:

- **Başlık (Header):** Kullanılan imzalama algoritması (`alg`) gibi belirteç hakkındaki
  meta verileri içerir.
- **Yük (Payload):** `issuer`, `credentialSubject` vb. dahil olmak üzere Doğrulanabilir
  Kimlik Bilgisinin (`vc` beyanı) gerçek beyanlarını içerir.
- **İmza (Signature):** Başlığı ve yükü kapsayan, yayıncı tarafından oluşturulan dijital
  imza.

```
// Bir JWT yapısı örneği
[Başlık].[Yük].[İmza]
```

> **Not:** JWT tabanlı Doğrulanabilir Kimlik Bilgileri bu blog yazısının kapsamı
> dışındadır. Bu uygulama, W3C Doğrulanabilir Kimlik Bilgileri veya JWT tabanlı kimlik
> bilgileri yerine ISO mDoc kimlik bilgilerine ve OpenID4VP'ye odaklanmaktadır.

#### 2.4.4 Doğrulanabilir Sunum: Sahipliğin Kanıtlanması

Bir doğrulayıcının bir kimlik bilgisinin geçerli olduğunu bilmesi yeterli değildir; aynı
zamanda kimlik bilgisini _sunan_ kişinin meşru sahibi olduğunu da bilmesi gerekir. Bu,
birinin çalınan bir kimlik bilgisini kullanmasını önler.

Bu, bir **Doğrulanabilir Sunum (VP)** kullanılarak çözülür. Bir VP, **sahibinin kendisi
tarafından imzalanan** bir veya daha fazla VC etrafındaki bir sarmalayıcıdır.

Akış şu şekildedir:

1. Doğrulayıcı, kullanıcıdan bir kimlik bilgisi sunmasını ister.
2. Kullanıcının cüzdanı bir Doğrulanabilir Sunum oluşturur, gerekli kimlik bilgilerini
   içine paketler ve tüm sunumu **sahibinin özel anahtarını** kullanarak imzalar.
3. Cüzdan bu imzalı VP'yi doğrulayıcıya gönderir.

Doğrulayıcımızın daha sonra **iki** ayrı imza kontrolü yapması gerekir:

1. **Kimlik Bilgilerini Doğrulama:** Sunum içindeki her VC'nin imzasını **yayıncının açık
   anahtarını** kullanarak kontrol edin. (Kimlik bilgisinin gerçek olduğunu kanıtlar).
2. **Sunumu Doğrulama:** VP'nin kendisindeki imzayı **sahibinin açık anahtarını**
   kullanarak kontrol edin. (Bunu sunan kişinin sahibi olduğunu kanıtlar).

Bu iki seviyeli kontrol, hem kimlik bilgisinin orijinalliğini hem de onu sunan kişinin
kimliğini sağlayarak sağlam ve güvenli bir güven modeli oluşturur.

> **Not:** W3C VC ekosisteminde tanımlandığı şekliyle
> [Doğrulanabilir Sunumlar](https://www.corbado.com/tr/glossary/open-id-4-vp) kavramı bu blog yazısının kapsamı
> dışındadır. Buradaki Doğrulanabilir Sunum terimi, W3C VP'sine benzer şekilde davranan
> ancak W3C'nin [JSON-LD](https://www.corbado.com/glossary/json-ld) imza modelinden ziyade ISO mDoc semantiğine
> dayanan OpenID4VP `vp_token` yanıtını ifade eder. Bu kılavuz, W3C Doğrulanabilir
> Sunumları veya imza doğrulamaları yerine ISO mDoc kimlik bilgilerine ve OpenID4VP'ye
> odaklanmaktadır.

## 3. Mimariye Genel Bakış

Doğrulayıcı mimarimiz, web uygulamamızı kullanıcının mobil **CMWallet**'ı ile bağlamak
için tarayıcının yerleşik **Dijital Kimlik Bilgisi API**'sini güvenli bir aracı olarak
kullanır. Bu yaklaşım, tarayıcının yerel [QR kod](https://www.corbado.com/tr/blog/qr-kod-giris-kimlik-dogrulama)
görüntülemesini ve cüzdan iletişimini yönetmesine izin vererek akışı basitleştirir.

- **Ön Uç (Next.js & React):** Hafif, kullanıcıya dönük bir web sitesi. Görevi, arka
  uçumuzdan bir talep nesnesi almak, onu tarayıcının `navigator.credentials.get()`
  API'sine geçirmek, sonucu almak ve doğrulama için arka uçumuza iletmektir.
- **Arka Uç (Next.js API Rotaları):** Doğrulayıcının güç merkezi. Tarayıcı API'si için
  geçerli bir talep nesnesi oluşturur ve nihai doğrulama için ön uçtan kimlik bilgisi
  sunumunu almak üzere bir uç nokta sunar.
- **Tarayıcı (Credential API):** Kolaylaştırıcı. Ön uçumuzdan talep nesnesini alır,
  `openid4vp` protokolünü anlar ve yerel olarak bir QR kodu oluşturur. Ardından cüzdanın
  bir yanıt döndürmesini bekler.
- **CMWallet (Mobil Uygulama):** Kullanıcının cüzdanı. QR kodunu tarar, talebi işler,
  kullanıcı onayını alır ve imzalı yanıtı tarayıcıya geri gönderir.

İşte tam ve doğru akışı gösteren bir sıra diyagramı:

![Tarayıcının Dijital Kimlik Bilgileri API'sini kullanarak Doğrulama Akışı](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Mermaid_Chart_Create_complex_visual_diagrams_with_text_A_smarter_way_of_creating_diagrams_2025_07_24_233623_1b6ed9b957.svg)

**Akışın Açıklaması:**

1. **Başlatma:** Kullanıcı **Ön Uçumuzdaki** "Doğrula" düğmesine tıklar.
2. **Talep Nesnesi:** Ön uç, sorguyu ve bir nonce içeren bir talep nesnesi oluşturan ve
   ardından onu döndüren **Arka Uçumuzu** (`/api/verify/start`) çağırır.
3. **Tarayıcı API Çağrısı:** Ön uç, talep nesnesiyle `navigator.credentials.get()`
   çağrısını yapar.
4. **Yerel QR Kodu:** **Tarayıcı**, `openid4vp` protokolü talebini görür ve yerel olarak
   bir QR kodu görüntüler. `.get()` promise'i şimdi beklemede.

> **Not:** Bu QR kodu akışı masaüstü tarayıcılarda gerçekleşir. Mobil tarayıcılarda
> (deneysel bayrak etkinleştirilmiş Android Chrome), tarayıcı aynı cihazdaki uyumlu
> cüzdanlarla doğrudan iletişim kurabilir, bu da QR kodu tarama ihtiyacını ortadan
> kaldırır. Bu özelliği Android Chrome'da etkinleştirmek için
> `chrome://flags#web-identity-digital-credentials` adresine gidin ve bayrağı "Etkin"
> olarak ayarlayın.

5. **Tarama ve Sunma:** Kullanıcı QR kodunu **CMWallet** ile tarar. Cüzdan kullanıcı
   onayını alır ve Doğrulanabilir Sunumu tarayıcıya geri gönderir.
6. **Promise Çözümlenmesi:** Tarayıcı yanıtı alır ve ön uçtaki orijinal `.get()` promise'i
   nihayet çözümlenerek sunum yükünü teslim eder.
7. **Arka Uç Doğrulaması:** Ön uç, sunum yükünü arka uçumuzun `/api/verify/finish` uç
   noktasına **POST** eder. Arka uç, nonce'ı ve kimlik bilgisini doğrular.
8. **Sonuç:** Arka uç, ön uca nihai bir başarı veya başarısızlık mesajı döndürür ve bu da
   UI'yi günceller.

## 4. Doğrulayıcıyı Oluşturma

Standartlar, protokoller ve mimari akışı hakkında sağlam bir anlayışa sahip olduğumuza
göre, doğrulayıcımızı oluşturmaya başlayabiliriz.

> **Takip Edin veya Nihai Kodu Kullanın**
>
> Şimdi kurulum ve kod uygulamasını adım adım ele alacağız. Doğrudan bitmiş ürüne atlamayı
> tercih ederseniz, tam projeyi GitHub depomuzdan klonlayabilir ve yerel olarak
> çalıştırabilirsiniz.
>
> ```bash
> git clone https://github.com/corbado/digital-credentials-example.git
> ```

### 4.1 Projeyi Kurma

İlk olarak, yeni bir Next.js projesi başlatacağız, gerekli bağımlılıkları kuracağız ve
veritabanımızı başlatacağız.

#### 4.1.1 Next.js Uygulamasını Başlatma

Terminalinizi açın, projenizi oluşturmak istediğiniz dizine gidin ve aşağıdaki komutu
çalıştırın. Bu proje için App Router, TypeScript ve Tailwind CSS kullanıyoruz.

```bash
npx create-next-app@latest . --ts --eslint --tailwind --app --src-dir --import-alias "@/*" --use-npm
```

Bu komut, mevcut dizininizde yeni bir Next.js uygulamasının iskelesini oluşturur.

#### 4.1.2 Bağımlılıkları Yükleme

Ardından, CBOR çözümleme, veritabanı bağlantıları ve UUID oluşturmayı yönetecek
kütüphaneleri kurmamız gerekiyor.

```bash
npm install cbor-web mysql2 uuid @types/uuid
```

Bu komut şunları yükler:

- `cbor-web`: mdoc kimlik bilgisi yükünü çözmek için.
- `mysql2`: Veritabanımız için MySQL istemcisi.
- `uuid`: Benzersiz zorluk dizeleri oluşturmak için.
- `@types/uuid`: `uuid` kütüphanesi için TypeScript türleri.

#### 4.1.3 Veritabanını Başlatma

Arka ucumuz, OIDC oturum verilerini depolamak için bir MySQL veritabanı gerektirir, bu da
her doğrulama akışının güvenli ve durum bilgisiyle donatılmasını sağlar. Bunu
kolaylaştırmak için bir `docker-compose.yml` dosyası ekledik.

Depoyu klonladıysanız, sadece `docker-compose up -d` komutunu çalıştırabilirsiniz.
Sıfırdan oluşturuyorsanız, aşağıdaki içeriğe sahip `docker-compose.yml` adında bir dosya
oluşturun:

```yaml
services:
    mysql:
        image: mysql:8.0
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: rootpassword
            MYSQL_DATABASE: digital_credentials
            MYSQL_USER: app_user
            MYSQL_PASSWORD: app_password
        ports:
            - "3306:3306"
        volumes:
            - mysql_data:/var/lib/mysql
            - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
        healthcheck:
            test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
            timeout: 20s
            retries: 10

volumes:
    mysql_data:
```

Bu Docker Compose kurulumu ayrıca bir SQL başlatma betiği gerektirir. `sql` adında bir
dizin oluşturun ve içinde, gerekli tabloları ayarlamak için aşağıdaki içeriğe sahip
`init.sql` adında bir dosya oluşturun:

```sql
-- Create database if not exists
CREATE DATABASE IF NOT EXISTS digital_credentials;
USE digital_credentials;

-- Table for storing challenges
CREATE TABLE IF NOT EXISTS challenges (
    id VARCHAR(36) PRIMARY KEY,
    challenge VARCHAR(255) NOT NULL UNIQUE,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    used BOOLEAN DEFAULT FALSE,
    INDEX idx_challenge (challenge),
    INDEX idx_expires_at (expires_at)
);

-- Table for storing verification sessions
CREATE TABLE IF NOT EXISTS verification_sessions (
    id VARCHAR(36) PRIMARY KEY,
    challenge_id VARCHAR(36),
    status ENUM('pending', 'verified', 'failed', 'expired') DEFAULT 'pending',
    presentation_data JSON,
    verified_at TIMESTAMP NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (challenge_id) REFERENCES challenges(id) ON DELETE CASCADE,
    INDEX idx_challenge_id (challenge_id),
    INDEX idx_status (status)
);

-- Table for storing verified credentials data (optional)
CREATE TABLE IF NOT EXISTS verified_credentials (
    id VARCHAR(36) PRIMARY KEY,
    session_id VARCHAR(36),
    credential_type VARCHAR(255),
    issuer VARCHAR(255),
    subject VARCHAR(255),
    claims JSON,
    verified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (session_id) REFERENCES verification_sessions(id) ON DELETE CASCADE,
    INDEX idx_session_id (session_id),
    INDEX idx_credential_type (credential_type)
);
```

Her iki dosya da yerinde olduğunda, terminalinizi proje kökünde açın ve şunu çalıştırın:

```bash
docker-compose up -d
```

Bu komut, arka planda bir MySQL container'ı başlatacaktır.

### 4.2 Next.js Uygulamasının Mimari Genel Bakışı

Next.js uygulamamız, aynı projenin parçası olmalarına rağmen, ön uç ve arka uç arasındaki
görevleri ayırmak için yapılandırılmıştır.

- **Ön Uç (`src/app/page.tsx`):** Doğrulama akışını başlatan ve sonucu görüntüleyen tek
  bir [React](https://www.corbado.com/blog/react-passkeys) sayfası. Tarayıcının Dijital Kimlik Bilgisi API'si ile
  etkileşime girer.
- **Arka Uç API Rotaları (`src/app/api/verify/...`):**
    - `start/route.ts`: OpenID4VP talebini ve bir güvenlik nonce'unu oluşturur.
    - `finish/route.ts`: Cüzdandan sunumu alır (tarayıcı aracılığıyla), nonce'ı doğrular
      ve kimlik bilgisini çözer.
- **Kütüphane (`src/lib/`):**
    - `database.ts`: Tüm veritabanı etkileşimlerini yönetir (zorluklar oluşturma,
      oturumları doğrulama).
    - `crypto.ts`: CBOR tabanlı mDoc kimlik bilgisinin çözülmesini yönetir.

İşte iç mimariyi gösteren bir diyagram:

![NextJS İç Mimarisi](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Mermaid_Chart_Create_complex_visual_diagrams_with_text_A_smarter_way_of_creating_diagrams_2025_07_25_091202_f96ccb049f.svg)

### 4.3 Ön Ucu Oluşturma

Ön ucumuz kasıtlı olarak hafiftir. Birincil sorumluluğu, doğrulama akışı için kullanıcıya
dönük bir tetikleyici olarak hareket etmek ve hem arka ucumuzla hem de tarayıcının yerel
kimlik bilgisi işleme yetenekleriyle iletişim kurmaktır. Kendi içinde herhangi bir
karmaşık protokol mantığı içermez; hepsi delege edilmiştir.

Özellikle, ön uç şunları yönetecektir:

- **Kullanıcı Etkileşimi:** Kullanıcının süreci başlatması için "Doğrula" düğmesi gibi
  basit bir arayüz sağlar.
- **Durum Yönetimi:** Doğrulama devam ederken yükleme göstergelerini göstererek ve nihai
  başarı veya hata mesajını görüntüleyerek UI durumunu yönetir.
- **Arka Uç İletişimi (Talep):** `/api/verify/start`'ı çağırır ve cüzdanın tam olarak ne
  sunması gerektiğini açıklayan yapılandırılmış bir JSON yükü (`protocol`, `request`,
  `state`) alır.
- **Tarayıcı API Çağrısı:** Bu JSON nesnesini, yerel bir QR kodu oluşturan ve cüzdan
  yanıtını bekleyen `navigator.credentials.get()`'e verir.
- **Arka Uç İletişimi (Yanıt):** Tarayıcı API'si Doğrulanabilir Sunumu döndürdüğünde, bu
  verileri nihai sunucu tarafı doğrulama için `/api/verify/finish` uç noktamıza bir POST
  isteğinde gönderir.
- **Sonuçları Görüntüleme:** Arka uçtan gelen yanıta dayanarak, doğrulamanın başarılı mı
  yoksa başarısız mı olduğunu kullanıcıya bildirmek için UI'yi günceller.

Çekirdek mantık `startVerification` fonksiyonundadır:

```typescript
// src/app/page.tsx

const startVerification = async () => {
    setLoading(true);
    setVerificationResult(null);

    try {
        // 1. Tarayıcının API'yi destekleyip desteklemediğini kontrol et
        if (!navigator.credentials?.get) {
            throw new Error("Tarayıcı Credential API'sini desteklemiyor.");
        }

        // 2. Arka uçumuzdan bir talep nesnesi iste
        const res = await fetch("/api/verify/start");
        const { protocol, request } = await res.json();

        // 3. Bu nesneyi tarayıcıya ver – bu yerel QR kodunu tetikler
        const credential = await (navigator.credentials as any).get({
            mediation: "required",
            digital: {
                requests: [
                    {
                        protocol, // "openid4vp"
                        data: request, // dcql_query, nonce, vb. içerir
                    },
                ],
            },
        });

        // 4. Cüzdan yanıtını (tarayıcıdan) sunucu tarafı kontrolleri için finish uç noktamıza ilet
        const verifyRes = await fetch("/api/verify/finish", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(credential),
        });

        const result = await verifyRes.json();

        if (verifyRes.ok && result.verified) {
            setVerificationResult(`Başarılı: ${result.message}`);
        } else {
            throw new Error(result.message || "Doğrulama başarısız.");
        }
    } catch (err) {
        setVerificationResult(`Hata: ${(err as Error).message}`);
    } finally {
        setLoading(false);
    }
};
```

Bu fonksiyon, ön uç mantığının dört anahtar adımını gösterir: API desteğini kontrol etme,
arka uçtan talebi alma, tarayıcı API'sini çağırma ve sonucu doğrulama için geri gönderme.
Dosyanın geri kalanı, durum ve UI oluşturma için standart [React](https://www.corbado.com/blog/react-passkeys)
şablon kodudur ve bunu
[GitHub deposunda](https://github.com/corbado/digital-credentials-example)
görüntüleyebilirsiniz.

#### Neden `digital` ve `mediation: 'required'`?

`navigator.credentials.get()` çağrımızın daha basit örneklerden farklı göründüğünü fark
edebilirsiniz. Bunun nedeni, resmi
[W3C Dijital Kimlik Bilgileri API spesifikasyonuna](https://www.w3.org/TR/digital-credentials/#the-digital-credentials-api)
sıkı sıkıya bağlı kalmamızdır.

- **`digital` Üyesi:** Spesifikasyon, tüm dijital kimlik bilgisi taleplerinin bir
  `digital` nesnesi içinde iç içe olmasını gerektirir. Bu, bu API için açık,
  standartlaştırılmış bir ad alanı sağlar, onu diğer kimlik bilgisi türlerinden
  (`password` veya `federated` gibi) ayırır ve çakışmalar olmadan gelecekteki uzantılara
  izin verir.

- **`mediation: 'required'`:** Bu seçenek, önemli bir güvenlik ve kullanıcı deneyimi
  özelliğidir. Kullanıcının kimlik bilgisi talebini onaylamak için bir istemle (örneğin,
  biyometrik tarama, PIN girişi veya bir onay ekranı) aktif olarak etkileşimde bulunmasını
  zorunlu kılar. Bu olmadan, bir web sitesi potansiyel olarak arka planda kimlik
  bilgilerine sessizce erişmeye çalışabilir, bu da önemli bir gizlilik riski oluşturur.
  Arabuluculuğu zorunlu kılarak, kullanıcının her zaman kontrol sahibi olmasını ve her
  işlem için açık rıza vermesini sağlarız.

### 4.4 Arka Uç Uç Noktalarını Oluşturma

React UI yerinde olduğuna göre, şimdi sunucuda ağır işi yapan iki API rotasına ihtiyacımız
var:

1. **`/api/verify/start`** – bir OpenID4VP talebi oluşturur, MySQL'de tek kullanımlık bir
   zorluk devam ettirir ve her şeyi tarayıcıya geri verir.
2. **`/api/verify/finish`** – cüzdan yanıtını alır, zorluğu doğrular, kimlik bilgisini
   doğrular ve çözer ve son olarak UI'ye özlü bir JSON sonucu döndürür.

#### 4.4.1 `/api/verify/start`: OpenID4VP Talebini Oluştur

```typescript
// src/app/api/verify/start/route.ts
import { NextResponse } from "next/server";
import { v4 as uuidv4 } from "uuid";
import { createChallenge, cleanupExpiredChallenges } from "@/lib/database";

export async function GET() {
    // 1️⃣ Kısa ömürlü, rastgele bir nonce (zorluk) oluştur
    const challenge = uuidv4();
    const challengeId = uuidv4();
    const expiresAt = new Date(Date.now() + 5 * 60 * 1000);

    await createChallenge(challengeId, challenge, expiresAt);
    cleanupExpiredChallenges().catch(console.error);

    // 2️⃣ *Ne istediğimizi* açıklayan bir DCQL sorgusu oluştur
    const dcqlQuery = {
        credentials: [
            {
                id: "cred1",
                format: "mso_mdoc",
                meta: { doctype_value: "eu.europa.ec.eudi.pid.1" },
                claims: [
                    { path: ["eu.europa.ec.eudi.pid.1", "family_name"] },
                    { path: ["eu.europa.ec.eudi.pid.1", "given_name"] },
                    { path: ["eu.europa.ec.eudi.pid.1", "birth_date"] },
                ],
            },
        ],
    };

    // 3️⃣ Tarayıcının navigator.credentials.get() fonksiyonuna geçirebileceği bir nesne döndür
    return NextResponse.json({
        protocol: "openid4vp", // tarayıcıya hangi cüzdan protokolünü kullanacağını söyler
        request: {
            dcql_query: dcqlQuery, // NE sunulacağı
            nonce: challenge, // yeniden oynatma saldırılarına karşı
            response_type: "vp_token",
            response_mode: "dc_api", // cüzdan doğrudan /finish'e POST yapacak
        },
        state: {
            credential_type: "mso_mdoc", // sonraki kontroller için saklanır
            nonce: challenge,
            challenge_id: challengeId,
        },
    });
}
```

> **Anahtar parametreler**
>
> • **`nonce`** – talep ve yanıtı bağlayan kriptografik zorluk (yeniden oynatmayı önler).
> • **`dcql_query`** – tam olarak ihtiyacımız olan beyanları tanımlayan bir nesne. Bu
> kılavuz için, henüz sonuçlandırılmış bir standart olmamasına rağmen, Dijital Kimlik
> Bilgisi Sorgu Dili'nin son taslaklarından esinlenerek bir `dcql_query` yapısı
> kullanıyoruz. • **`state`** – cüzdan tarafından geri yansıtılan keyfi JSON, böylece
> veritabanı kaydını arayabiliriz.

#### 4.4.2 Veritabanı Yardımcıları

`src/lib/database.ts` dosyası, zorluklar ve doğrulama oturumları için temel MySQL
işlemlerini (ekleme, okuma, kullanıldı olarak işaretleme) sarmalar. Bu mantığı tek bir
modülde tutmak, veri deposunu daha sonra değiştirmeyi kolaylaştırır.

---

### 4.5 `/api/verify/finish`: Sunumu Doğrula ve Çöz

```typescript
// src/app/api/verify/finish/route.ts
import { NextResponse, NextRequest } from "next/server";
import { v4 as uuidv4 } from "uuid";
import {
    getChallenge,
    markChallengeAsUsed,
    createVerificationSession,
    updateVerificationSession,
} from "@/lib/database";
import { decodeDigitalCredential, decodeAllNamespaces } from "@/lib/crypto";

export async function POST(request: NextRequest) {
    const body = await request.json();

    // 1️⃣ Doğrulanabilir sunum parçalarını çıkar
    const vpTokenMap = body.vp_token ?? body.data?.vp_token;
    const state = body.state;
    const mdocToken = vpTokenMap?.cred1; // bu ID'yi dcqlQuery'de istemiştik

    if (!vpTokenMap || !state || !mdocToken) {
        return NextResponse.json(
            { verified: false, message: "Hatalı biçimlendirilmiş yanıt" },
            { status: 400 },
        );
    }

    // 2️⃣ Tek kullanımlık zorluk doğrulaması
    const stored = await getChallenge(state.nonce);
    if (!stored) {
        return NextResponse.json(
            { verified: false, message: "Geçersiz veya süresi dolmuş zorluk" },
            { status: 400 },
        );
    }

    const sessionId = uuidv4();
    await createVerificationSession(sessionId, stored.id);

    // 3️⃣ (Sözde) kriptografik kontroller – prod'da gerçek mDL doğrulamasıyla değiştirin
    // Gerçek bir uygulamada, mdoc imzasının yayıncının açık anahtarına karşı
    // tam kriptografik doğrulamasını yapmak için özel bir kütüphane kullanırdınız.
    const isValid = mdocToken.length > 0;
    if (!isValid) {
        await updateVerificationSession(sessionId, "failed", {
            reason: "mdoc doğrulaması başarısız",
        });
        return NextResponse.json(
            { verified: false, message: "Kimlik bilgisi doğrulaması başarısız" },
            { status: 400 },
        );
    }

    // 4️⃣ Mobil sürücü belgesi (mdoc) yükünü insan tarafından okunabilir JSON'a çöz
    const decoded = await decodeDigitalCredential(mdocToken);
    const readable = decodeAllNamespaces(decoded)["eu.europa.ec.eudi.pid.1"];

    await markChallengeAsUsed(state.nonce);
    await updateVerificationSession(sessionId, "verified", { readable });

    return NextResponse.json({
        verified: true,
        message: "mdoc kimlik bilgisi başarıyla doğrulandı!",
        credentialData: readable,
        sessionId,
    });
}
```

> **Cüzdan yanıtındaki önemli alanlar**
>
> • **`vp_token`** – cüzdanın döndürdüğü _her_ kimlik bilgisini tutan harita. Demomuz için
> `vp_token.cred1`'i çekiyoruz. • **`state`** – `/start`'ta sağladığımız blobun yankısı;
> veritabanı kaydını arayabilmemiz için `nonce`'u içerir. • **`mdocToken`** – ISO mDoc'u
> temsil eden Base64URL ile kodlanmış bir CBOR yapısı.

### 4.6 mdoc Kimlik Bilgisini Çözme

Doğrulayıcı, tarayıcıdan bir mdoc kimlik bilgisi aldığında, bu, CBOR ile kodlanmış ikili
veriler içeren bir Base64URL dizesidir. Gerçek beyanları çıkarmak için, `finish` uç
noktası `src/lib/crypto.ts`'den yardımcı fonksiyonlar kullanarak çok adımlı bir çözme
işlemi gerçekleştirir.

#### 4.6.1 Adım 1: Base64URL ve CBOR Çözme

`decodeDigitalCredential` fonksiyonu, kodlanmış dizeden kullanılabilir bir nesneye
dönüşümü yönetir:

```typescript
// src/lib/crypto.ts
export async function decodeDigitalCredential(encodedCredential: string) {
    // 1. Base64URL'yi standart Base64'e dönüştür
    const base64UrlToBase64 = (input: string) => {
        let base64 = input.replace(/-/g, "+").replace(/_/g, "/");
        const pad = base64.length % 4;
        if (pad) base64 += "=".repeat(4 - pad);
        return base64;
    };

    const base64 = base64UrlToBase64(encodedCredential);

    // 2. Base64'ü ikiliye çöz
    const binaryString = atob(base64);
    const byteArray = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));

    // 3. CBOR'u çöz
    const decoded = await cbor.decodeFirst(byteArray);
    return decoded;
}
```

- **Base64URL'den Base64'e:** Kimlik bilgisini Base64URL'den standart Base64 kodlamasına
  dönüştürür.
- **Base64'ten İkiliye:** Base64 dizesini bir ikili bayt dizisine çözer.
- **CBOR Çözme:** İkili verileri yapılandırılmış bir JavaScript nesnesine çözmek için
  `cbor-web` kütüphanesini kullanır.

#### 4.6.2 Adım 2: Ad Alanına Sahip Beyanları Çıkarma

`decodeAllNamespaces` fonksiyonu, ilgili ad alanlarından gerçek beyanları çıkarmak için
çözülmüş CBOR nesnesini daha fazla işler:

```typescript
// src/lib/crypto.ts
export function decodeAllNamespaces(jsonObj) {
    const decoded = {};

    try {
        jsonObj.documents.forEach((doc, idx) => {
            // 1) issuerSigned.nameSpaces:
            const issuerNS = doc.issuerSigned?.nameSpaces || {};
            Object.entries(issuerNS).forEach(([nsName, entries]) => {
                if (!decoded[nsName]) decoded[nsName] = {};
                (entries as any[]).forEach((entry) => {
                    const bytes = Uint8Array.from(entry.value);
                    const decodedEntry = cbor.decodeFirstSync(bytes);
                    Object.assign(decoded[nsName], decodedEntry);
                });
            });

            // 2) deviceSigned.nameSpaces (varsa):
            const deviceNS = doc.deviceSigned?.nameSpaces;
            if (deviceNS?.value?.data) {
                const bytes = Uint8Array.from(deviceNS.value);
                decoded[`deviceSigned_ns_${idx}`] = cbor.decodeFirstSync(bytes);
            }
        });
    } catch (e) {
        console.error(e);
    }

    return decoded;
}
```

- Çözülmüş kimlik bilgisindeki **tüm belgeler üzerinde döner**.
- Gerçek beyan değerlerini (ad, doğum tarihi vb. gibi) çıkarmak için **her ad alanını**
  (örneğin, `eu.europa.ec.eudi.pid.1`) **çözer**.
- Varsa, **hem yayıncı tarafından imzalanmış hem de cihaz tarafından imzalanmış ad
  alanlarını** yönetir.

#### Örnek Çıktı

Bu adımları çalıştırdıktan sonra, finish uç noktası mdoc'tan beyanları içeren insan
tarafından okunabilir bir nesne elde eder, örneğin:

```json
{
    "family_name": "Doe",
    "given_name": "John",
    "birth_date": "1990-01-01"
}
```

Bu süreç, doğrulayıcının görüntüleme ve daha fazla işleme için mdoc kimlik bilgisinden
gerekli bilgileri güvenli ve güvenilir bir şekilde çıkarabilmesini sağlar.

### 4.7 Sonucu UI'de Gösterme

Finish uç noktası, ön uca minimal bir JSON nesnesi döndürür:

```json
{
    "verified": true,
    "message": "mdoc kimlik bilgisi başarıyla doğrulandı!",
    "credentialData": {
        "family_name": "Doe",
        "given_name": "John",
        "birth_date": "1990-01-01"
    }
}
```

Ön uç bu yanıtı `startVerification()` içinde alır ve sadece React durumunda saklar,
böylece güzel bir onay kartı oluşturabilir veya bireysel beyanları görüntüleyebiliriz –
örneğin, _"Hoş geldiniz, John Doe (doğum tarihi 1990-01-01)!"_.

## 5. Doğrulayıcıyı Çalıştırma ve Sonraki Adımlar

Şimdi tarayıcının yerel kimlik bilgisi işleme yeteneklerini kullanan eksiksiz, çalışan bir
doğrulayıcınız var. İşte onu yerel olarak nasıl çalıştıracağınız ve bir kavram kanıtından
üretime hazır bir uygulamaya nasıl götürebileceğiniz.

### 5.1 Örneği Nasıl Çalıştırılır

1. **Depoyu Klonlayın:**

    ```bash
    git clone https://github.com/corbado/digital-credentials-example.git
    cd digital-credentials-example
    ```

2. **Bağımlılıkları Yükleyin:**

    ```bash
    npm install
    ```

3. **Veritabanını Başlatın:** Docker'ın makinenizde çalıştığından emin olun, ardından
   MySQL container'ını başlatın:

    ```bash
    docker-compose up -d
    ```

4. **Uygulamayı Çalıştırın:**

    ```bash
    npm run dev
    ```

    Tarayıcınızı `http://localhost:3000` adresinde açtığınızda doğrulayıcının UI'sini
    görmelisiniz. Artık QR kodunu taramak ve doğrulama akışını tamamlamak için
    CMWallet'ınızı kullanabilirsiniz.

### 5.2 Sonraki Adımlar: Demodan Üretime

Bu eğitim, bir doğrulayıcı için temel yapı taşlarını sağlar. Üretime hazır hale getirmek
için, birkaç ek özellik uygulamanız gerekir:

- **Tam Kriptografik Doğrulama:** Mevcut uygulama bir yer tutucu kontrolü
  (`mdocToken.length > 0`) kullanır. Gerçek dünya senaryosunda, mdoc imzasının yayıncının
  açık anahtarına karşı tam kriptografik doğrulamasını yapmanız gerekir (örneğin,
  DID'lerini çözerek veya açık anahtar sertifikalarını alarak). DID çözümleme standartları
  için [W3C DID Çözümleme spesifikasyonuna](https://www.w3.org/TR/did-resolution/) bakın.

- **Yayıncı İptal Kontrolü:** Kimlik bilgileri, son kullanma tarihlerinden önce yayıncı
  tarafından iptal edilebilir. Bir üretim doğrulayıcısı, yayıncı tarafından sağlanan bir
  iptal listesini veya durum uç noktasını sorgulayarak kimlik bilgisinin durumunu kontrol
  etmelidir.
  [W3C Doğrulanabilir Kimlik Bilgileri Durum Listesi](https://www.w3.org/TR/vc-bitstring-status-list/),
  kimlik bilgisi iptal listeleri için standardı sağlar.

- **Sağlam Hata Yönetimi ve Güvenlik:** Kapsamlı hata yönetimi, girdi doğrulama, API uç
  noktalarında hız sınırlama ekleyin ve aktarımdaki verileri korumak için tüm iletişimin
  HTTPS (TLS) üzerinden olduğundan emin olun.
  [OWASP API Güvenlik Yönergeleri](https://owasp.org/www-project-api-security/), kapsamlı
  API güvenlik en iyi uygulamalarını sağlar.

- **Çoklu Kimlik Bilgisi Türleri Desteği:** Yalnızca Avrupa Dijital Kimliği (EUDI) PID
  kimlik bilgisinden daha fazlasını almayı bekliyorsanız, farklı `doctype` değerlerini ve
  kimlik bilgisi formatlarını işlemek için mantığı genişletin.
  [W3C Doğrulanabilir Kimlik Bilgileri Veri Modeli](https://www.w3.org/TR/vc-data-model/),
  kapsamlı VC formatı spesifikasyonları sağlar.

### 5.3 Bu Eğitimin Kapsamı Dışında Kalanlar

Bu örnek, anlaşılmasını kolaylaştırmak için kasıtlı olarak çekirdek tarayıcı aracılı akışa
odaklanmıştır. Aşağıdaki konular kapsam dışı kabul edilir:

- **Üretime Hazır Güvenlik:** Doğrulayıcı eğitim amaçlıdır ve canlı bir ortam için gereken
  sağlamlaştırmadan yoksundur.
- **W3C Doğrulanabilir Kimlik Bilgileri:** Bu eğitim yalnızca mobil sürücü belgeleri için
  ISO mDoc formatına odaklanmaktadır. JWT-VC'ler veya Bağlantılı Veri Kanıtları
  (LD-Proofs) olan VC'ler gibi diğer popüler formatları kapsamaz.
- **Gelişmiş OpenID4VP Akışları:** Bir `redirect_uri` kullanarak doğrudan cüzdandan arka
  uca iletişim veya dinamik istemci kaydı gibi daha karmaşık OpenID4VP özelliklerini
  uygulamıyoruz.

Bu temel üzerine inşa ederek ve bu sonraki adımları dahil ederek, kendi uygulamalarınızda
dijital kimlik bilgilerini güvenebilen ve doğrulayabilen sağlam ve güvenli bir doğrulayıcı
geliştirebilirsiniz.

## Sonuç

İşte bu kadar! 250 satırdan az TypeScript ile şimdi uçtan uca bir doğrulayıcımız var:

1. Tarayıcının kimlik bilgisi API'si için bir talep yayınlar.
2. Herhangi bir uyumlu cüzdanın bir Doğrulanabilir Sunum sağlamasına izin verir.
3. Sunucuda sunumu doğrular.
4. UI'yi gerçek zamanlı olarak günceller.

Üretimde, yer tutucu doğrulamayı tam [ISO 18013-5](https://www.corbado.com/glossary/iso-18013-5) kontrolleriyle
değiştirir, yayıncı iptal sorguları, hız sınırlama, denetim günlüğü ve tabii ki uçtan uca
TLS eklersiniz—ancak çekirdek yapı taşları tamamen aynı kalır.

## Kaynaklar

İşte bu eğitimde kullanılan veya referans verilen bazı anahtar kaynaklar, spesifikasyonlar
ve araçlar:

- **Proje Deposu:**
    - [GitHub'daki Tam Kaynak Kodu](https://github.com/corbado/digital-credentials-example)

- **Anahtar Spesifikasyonlar:**
    - [W3C Doğrulanabilir Kimlik Bilgileri Veri Modeli](https://www.w3.org/TR/vc-data-model/):
      VC'ler için temel standart.
    - [Doğrulanabilir Sunumlar için OpenID (OpenID4VP)](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html):
      Kimlik bilgisi değişimi için kullanılan sunum protokolü.
    - [ISO/IEC 18013-5 (mDoc)](https://www.iso.org/standard/69084.html): Mobil Sürücü
      Belgeleri (mDL'ler) için uluslararası standart.
    - [W3C Dijital Kimlik Bilgileri API'si](https://www.w3.org/TR/digital-credentials/#the-digital-credentials-api):
      Bir cüzdandan kimlik bilgisi talep etmek için kullanılan tarayıcı API'si.

- **Araçlar:**
    - [Android için CMWallet](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220):
      Bu kılavuzda kullanılan test cüzdanı.

- **Kütüphaneler:**
    - Next.js: Ön uç ve arka ucu oluşturmak için React çerçevesi.
    - [cbor-web](https://github.com/hildjj/cbor-web): CBOR ile kodlanmış mdoc kimlik
      bilgilerini çözmek için.
    - [mysql2](https://github.com/sidorares/node-mysql2): [Node.js](https://www.corbado.com/blog/nodejs-passkeys)
      için MySQL istemcisi.
