Skip to content
GUIDE-0001Rehber · IntegrationTaslaksürüm 0.1.02026-09-27T00:00:00.000Z

Web sitesine "TamgaID ile Kayıt Ol / Giriş Yap" ​

Nasıl çalışır ​

  1. Kayıt (bir kez): siteniz bir politika ile istek başlatır (ör. "ad, soyad, hesap anahtarı"). Bilgisayarda QR, telefonda "Tamga Wallet'ta aç" düğmesi çıkar. Kişi cüzdanda yalnızca bu alanları görür ve onaylar.
  2. Doğrulayıcı sunumu doğrular (imza, güven listesi, iptal, cihaz bağı). Sayfanız sonucu yoklar; ACCEPTED olunca presentation_id'yi kendi sunucunuza gönderir. Sunucunuz onaylanan alanları doğrulayıcıdan alır, hesabı açar, oturum çerezi verir.
  3. Passkey (önerilir): kayıttan hemen sonra "Bu cihaza passkey ekle". Sonraki girişler Face ID / parmak izi — cüzdan açılmaz, hiçbir alan paylaşılmaz, passkey yalnızca sizin sitenize özeldir.
  4. Yeni cihaz / passkey yok: "TamgaID ile Giriş" yalnızca hesap anahtarını ister; sonra yine passkey eklenir.

1. Sunucu: sunumu siz açarsınız (ADR-0017) ​

Barındırılan doğrulayıcıya her çağrı, sitenizin güven listesindeki erişim sertifikasının anahtarıyla imzalı kısa ömürlü bir beyan taşır (Authorization: Bearer …, ≤ 60 sn, tek kullanım). Yeni bir şifre yoktur; anahtar, kaydınızdaki sertifikanınkidir.

ts
import { createRpAssertion, pemRpSigner } from "@tamga-network/verifier";
const rp = await pemRpSigner(RP_KEY_PEM, RP_CERT_PEM, "x509_san_dns:ornek.com.tr");
const auth = async () => ({ authorization: `Bearer ${await createRpAssertion(rp, VERIFIER)}` });

// POST /tamga/start { policy }  → sayfaya: { presentation_id, qr_payload, expires_at, status_token }
const r = await fetch(`${VERIFIER}/presentations`, { method: "POST",
  headers: { ...(await auth()), "content-type": "application/json", accept: "application/json" },
  body: JSON.stringify({ policy_id: policy }) }).then((x) => x.json());

Cüzdan onay ekranında sitenizin kayıtlı adı görünür ("aracı doğrulayıcı: verify.tamga.network" notuyla); istenen alanlar kaydınızın kapsamına göre denetlenir (HV6, AP6).

2. Sayfa ​

<script> ile (doğrulayıcı kiti paketlenmiş sunar):

html
<script src="https://verify.tamga.network/tamga-verifier.js"></script>
<div id="tamga"></div>
<script>
  TamgaVerifier.mount(document.getElementById("tamga"), {
    verifier: "https://verify.tamga.network",
    policy: "site-uyelik", // giriş için "site-giris"
    start: () => fetch("/tamga/start", { method: "POST", headers: { "content-type": "application/json" },
                                          body: JSON.stringify({ policy: "site-uyelik" }) }).then((r) => r.json()),
    onResult: (presentationId) =>
      fetch("/oturum", { method: "POST", headers: { "content-type": "application/json" },
                         body: JSON.stringify({ presentation_id: presentationId }) }).then(() => location.reload()),
  });
</script>

npm ile: import { mount, passkey } from "@tamga-network/verifier/web" (aynı arayüz). Kit doğrulama yapmaz ve değer görmez: yalnızca status_token ile durumu izler; karar ve değerler sunucunuzdadır. onError INDETERMINATE durumunu ayrı gösterir ("şu an doğrulanamadı — tekrar deneyin"; belge geçersiz demek değildir).

3. Sunucu: oturum açma ​

ts
// POST /oturum { presentation_id }  — yalnızca JSON kabul edin (CSRF), Origin aynı site olmalı
const r = await fetch(`${VERIFIER}/presentations/${id}`, { headers: await auth() }).then((x) => x.json());
if (r.outcome !== "ACCEPTED") return res.status(400).send();       // INDETERMINATE → "tekrar deneyin"
const { claims } = await fetch(`${VERIFIER}/presentations/${id}/claims`, { headers: await auth() }).then((x) => x.json());
// değerler BİR KEZ verilir (ikinci okuma 410) ve sonuçtan 5 dk sonra silinir — hemen işleyin
const hesapAnahtari = hmacSha256(SITE_SIRRI, claims.document_number_hash); // ham değeri SAKLAMAYIN

Sonucu ve değerleri yalnızca sunumu açan site alabilir; başka biri sunum kimliğini bilse de 404 alır (HV1–HV4). Kurallar (örnek sitede uygulanmış hâlleri: apps/verify/src/routes/site.ts):

  • Tek kullanım: bir sunum yalnızca bir oturum açar.
  • Politika denetimi: yalnızca kendi site politikalarınızla yapılmış sunumu kabul edin.
  • Hesap anahtarı: document_number_hash'in kendisini değil, site sırrınızla HMAC'ını saklayın. Aynı değer her siteye gittiği için ham değer siteler arası eşleştirmeye yarar (S-17).
  • Çerez: HttpOnly; SameSite=Lax; Secure; sunucu tarafında süre; CSRF için yalnızca JSON + Origin kontrolü.
  • Kişisel veri loglanmaz (ad, anahtar, passkey kimliği dahil).

4. Passkey (WebAuthn) ​

Sunucu tarafı için bir WebAuthn kütüphanesi (örnek sitede @simplewebauthn/server): kayıt ve giriş için options + verify uçları; attestation: "none", residentKey: "required", userVerification: "required". Sayfa tarafı:

js
const o = await post("/passkey/register/options");     // oturum açıkken
await post("/passkey/register/verify", await TamgaVerifier.passkey.create(o));
// giriş: const { flow, options } = await post("/passkey/login/options");
//        await post("/passkey/login/verify", { flow, response: await TamgaVerifier.passkey.get(options) });

WebAuthn IP adresinde çalışmaz: localhost ya da HTTPS alan adı gerekir (rpID = sayfanın alan adı).

5. Üretime geçmeden önce ​

  • Siteniz Tamga güven listesinde bir RP (doğrulayıcı) kaydı ister; istediğiniz alanlar kaydın kapsamını aşamaz (AP6).
  • Barındırılan doğrulayıcı üretimde beyansız isteği reddeder (TAMGA_VERIFY_REQUIRE_RP_AUTH=1); demo/LAN kipinde beyansız eski yol Deprecation başlığıyla çalışır. İsterseniz doğrulamayı tamamen kendi sunucunuzda yapın: GUIDE-0002.
  • Politika adları ve alan setleri Tamga ile birlikte belirlenir (ör. yalnızca "18 yaşından büyük" → yas-dogrulama-mdoc).