Appearance
Web sitesine "TamgaID ile Kayıt Ol / Giriş Yap"
Nasıl çalışır
- 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.
- Doğrulayıcı sunumu doğrular (imza, güven listesi, iptal, cihaz bağı). Sayfanız sonucu yoklar;
ACCEPTEDoluncapresentation_id'yi kendi sunucunuza gönderir. Sunucunuz onaylanan alanları doğrulayıcıdan alır, hesabı açar, oturum çerezi verir. - 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.
- 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 SAKLAMAYINSonucu 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 yolDeprecationbaş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).