Ana içeriğe geç

00 · AUTH — Açılış Sözleşmesi

Görev: Uygulama açıldığında kimliği doğrular, güncel config versiyonlarını ve bir token döndürür; açılışta ne yapılacağına dair karar (decision) verir.

Ne zaman çalışır: Her uygulama açılışında — ilk çalıştırmada ve sonrasında her seferinde.

Bu dosyayı örnek istek/yanıtlarla birlikte okuyun: JSON'lar doldurulmuş örnektir; bölümdeki tablolar alanların anlamını anlatır.


1. Genel Bakış

AUTH, döngünün ilk ve her seferinde çalışan adımıdır. SDK sunucuya iki şey gönderir:

  • KimlikapiKey + packageName + platform + consentId
  • Cihazda önbelleklediği mevcut durumulocalState (kurulu versiyonlar + önceki onay haritası)

Sunucu karşılığında üç şey döndürür:

  • VersiyonlarschemaVersion / uiVersion / legalVersion / contentVersion
  • Token → oturum bazlı config token'ı (tokenExpiresIn saniye ile geçerlilik)
  • Karardecision: config yenileme mi, tekrar sor (reprompt) mu, yoksa sessizce devam mı?

Tasarım felsefesi: AUTH hafif ve hızlı tutulur. Güncel config (tema, ekranlar, gruplar, metinler — büyük gövde) yalnızca değiştiğinde, decision.updateRequired === true olduğunda, bir sonraki adım olan 01 · GET /config ile çekilir. İçerik değişmiyorsa config hiç transfer edilmez → açılış hızlı, veri tasarruflu, gecikme düşük.


2. İki Aşamalı Açılış Akışı

┌──────────────┐ kimlik + localState ┌──────────────┐
│ SDK (App) │ ─────────────────────▶ │ SUNUCU │
│ │ ◀───────────────────── │ │
└──────────────┘ versiyon + token + decision └──────────────┘

decision.updateRequired ?
┌───────────────┴───────────────┐
│ TRUE │ FALSE
▼ ▼
GET /config (01) Mevcut config'i
token ile tam config indir, cihazdaki önbellekten
parse et, önbelleğe yaz, kullan; sürüye devam et
UI'ı yeniden kur


decision.retriggerRequired /
showConsentOnLaunch → onay ekranını göster mi?
AdımKoşulSDK davranışı
1 — AUTH (bu sözleşme)Her açılıştaKimlik + localState gönder; versiyon + token + decision al
2 — GET /configdecision.updateRequired === true iseToken ile tam config indir, parsel et, önbelleğe yaz, UI'ı yeniden kur
3 — Onay kararıshowConsentOnLaunch veya retriggerRequired true iseOnay ekranını (banner/manager) göster; aksi halde sessiz devam

3. Endpoint & Güvenlik

3.1 Endpoint

ÖzellikDeğer
MethodPOST
Path/v2/consent/{consentId}/auth
Base URL{{SDK_BASE_URL}}
Gövde formatıapplication/json (UTF-8)
Timeout15 sn
IdempotentEvet — aynı istek tekrarlandığında aynı sonucu verir

3.2 Güvenlik (imza ile sahte/replay istek koruması)

Kimlik doğrulaması yalnız apiKey ile değil, HMAC imza + nonce + zaman damgası üçlüsüyle yapılır. İstek şunları taşır:

HeaderDeğer / Formül
Content-Typeapplication/json
X-Consent-SDK-KeyapiKey (body'deki apiKey'ye alternatif; üretimde header tercih edilir)
X-Consent-SignatureHMAC-SHA256(apiKey, packageName + platform + requestTimestamp + nonce) — hex kodlanmış
X-Request-Timestampepoch milliseconds
X-NonceTek kullanımlık rastgele string
  • Algoritma: HMAC-SHA256
  • İmza girdisi (canonical): packageName + platform + requestTimestamp + nonce
  • Replay penceresi: ±300 sn. Penceresi dışındaki timestamp veya tekrar eden nonce → 401 REPLAY_DETECTED.

AUTH ve POST_CONSENT yazma/durum değiştirici sözleşmeler olduğu için imza/nonce/timestamp zorunludur. (GET /config bir okuma işlemidir; orada imza yerine yalnız token kullanılır — 01 · GET /config §3.)


4. İstek (request)

Uygulamanın gönderdiği gövde. Kimlik alanları zorunludur; geriye kalanlar isteğe bağlıdır ama kararın doğruluğunu artırır. camelCase zorunludur.

AlanTipZorunluAçıklama
apiKeystringEvetUygulamanın gizli API anahtarı (kendi Apps Console'undan). Yanlış/çözülmüş anahtar → 401 INVALID_API_KEY.
consentIdstringEvetOnay kaydının benzersiz kimliği (ör. ck_mobildev_0001). Hangi consent setinin çözüleceğini belirler. Path'teki {consentId}'yle birebir aynı olmalıdır.
packageNamestringEvetPaket/identifier. Android: reverse-domain (com.mobildev.app); iOS: bundle id (com.mobildev.ios). apiKey'nin bu package'a tanımlı olup olmadığı doğrulanır; uyuşmazlık → 403 PACKAGE_MISMATCH.
platformenum iOS | AndroidEvetHedef platform. Paket formatı, platform bazlı davranış (örn. iOS ATT) ve şema feature-gate kararı buna göre çözülür.
sdkVersionstring (semver)EvetSDK paketinin sürümü. schemaVersion ile birlikte feature-gate kararında kullanılır; eski SDK yeni şemayı çözemiyorsa uyumlu config setine yönlendirilir.
appVersionstring (semver)HayırMüşteri uygulamanın sürümü. Telemetri/korelasyon için; auth kararını doğrudan etkilemez.
buildNumberintegerHayıriOS CFBundleVersion / Android versionCode. Aynı appVersion içinde farklı build'leri ayırt eder.
localestring (BCP-47)HayırKullanıcı dili (ör. tr-TR). Config'in availableLanguages'inde varsa o dil, yoksa defaultLanguage çözülür.
deviceTimestring (ISO 8601 UTC)HayırCihaz saati. Sunucu saatiyle drift/manipülasyon kontrolü; aşırı drift → 400 CLOCK_DRIFT.
deviceobjectHayırmodel, osVersion. Hata teşhis ve uyumluluk raporlama içindir; auth kararında doğrudan kullanılmaz.
localStateobjectHayırCihazda önbelleklenen mevcut durum. Sunucunun karar üretmesinin geri beslemesidir (aşağıda detay). İlk çalıştırmada null/boş bırakılır.

4.1 localState Alt Alanları

AlanTipAçıklama
hasConsentbooleanBu cihazda daha önce onay var mı? false = ilk açılış → ilk onay ekranı gösterilir.
installedUiVersionstring | nullÖnbellekteki UI/theme/layout versiyonu. Remote uiVersion'dan düşükse görünüm yenilenir (reprompt yok).
installedLegalVersionstring | nullÖnbellekteki legal/metin versiyonu. Remote'dan yüksekse metin yenilenir ve onay varsa reprompt.
installedContentVersionstring | nullÖnbellekteki içerik versiyonu. Remote'dan yüksekse retriggerRequired = true (içerik değişti → tekrar sor).
lastShownAtstring | null (ISO 8601)Onay ekranının son gösterildiği an. Config'de retrigger.interval tanımlıysa bu değer interval'ı aşarsa zaman bazlı reprompt devreye girer.
consentobject | nullÖnceki onay haritası. Anahtarlar groupId'lerdir (essential/functionality/targeting/tracking); değerler yalnız granted / denied. Bir sonraki adım (02 · POST_CONSENT'in localState) ile birebir aynı yapıdır — burada geri beslemesi için gönderilir.

4.2 Örnek İstek (ilki açılış — localState boş)

{
"apiKey": "sk_live_9f2ac41ab88e3d5c7e9f",
"consentId": "ck_mobildev_0001",
"packageName": "com.mobildev.app",
"platform": "Android",
"sdkVersion": "1.4.0",
"appVersion": "2.8.0",
"buildNumber": 280,
"locale": "tr-TR",
"deviceTime": "2026-09-20T11:33:29Z",
"device": { "model": "Pixel 9", "osVersion": "Android 15" },
"localState": {
"hasConsent": false,
"installedUiVersion": null,
"installedLegalVersion": null,
"installedContentVersion": null,
"lastShownAt": null,
"consent": null
}
}

Daha sonraki açılışlarda localState dolu gelir (02 adımında sunucunun döndürdüğü localState, buraya aynen kopyalanır). Doğru retrigger kararı bu bloğun doluluğuna bağlıdır. Bu örneğin aynısı ayrıca [00-auth.request.json](./00-auth.request.json) dosyasında yer alır.


5. Yanıt (response)

5.1 Gövde Alanları (200)

AlanTipAçıklama
successbooleanİsteğin başarıyla tamamlandığı.
codestringDurum kodu (başarıda OK).
consentIdstringÇözülen consentId (eko; log/teşhis).
schemaVersionstringSDK feature-gate versiyonu (örn. 2.0). Eski SDK uyumlu set kullanır.
uiVersionstringMevcut UI/theme/layout versiyonu. Cihazdaki installedUiVersion'dan yüksekse görünüm yenilenir (reprompt değil, yalnız görsel).
legalVersionstringMevcut legal/metin versiyonu. Cihazdaki installedLegalVersion'dan yüksekse metin yenilenir ve onay varsa reprompt.
contentVersionstringMevcut içerik versiyonu. Cihazdaki installedContentVersion'dan yüksekse retriggerRequired = true.
contentModeenum sample | productionİçerik modu. sample → geliştirme/test verisi.
generatedAtstring (ISO 8601)Config'in sunucuda yayınlanma/üretim zamanı.
tokenstringGET /config ve POST_CONSENT'te kullanılacak imzalı, oturum bazlı token (örn. cfg_t_8a3f5c2d1e0b).
tokenExpiresInintegerToken geçerlilik süresi (saniye). Dolunca yeniden AUTH yapılır.
decisionobjectSDK'nın açılışta ne yapacağını belirten karar bloğu (aşağıda).

Versiyon modeli — üç bağımsız katman: schemaVersion (şema/SDK feature-gate) · uiVersion (görünüm) · legalVersion + contentVersion (içerik). Bu ayrım, "yalnız görsel değişti" ile "içerik/majör şema değişti" arasındaki reprompt farkını üretir: içerik veya majör şema değişimi reprompt üretir; yalnız görsel değişimi reprompt üretmez (görsel yenilenir).

5.2 decision Alt Alanları

AlanTipAçıklama
updateRequiredbooleantrue → config yenileme gerekli; token ile GET /config yapılır.
retriggerRequiredbooleantrue → onay mevcut ama içerik/majör değişiklik var; onay ekranı yeniden gösterilir.
showConsentOnLaunchbooleanBu açılışta onay ekranının gösterilip gösterilmeyeceği. İlk çalıştırmada veya retrigger gerekliyse true; config değişimi yoksa false.
reasonsarray<enum>Kararı üreten nedenler (çeşitli olabilir). Loglama/teşhis.

reasons değerleri: FIRST_RUN, NO_CACHED_CONFIG, CONTENT_UPDATED, LEGAL_UPDATED, UI_UPDATED, INTERVAL_RETRIGGER, MAJOR_SCHEMA_CHANGE, TOKEN_EXPIRED, NO_CHANGE.

5.3 Örnek Yanıt (ilk açılış — config + onay ekranı gerekli)

{
"success": true,
"code": "OK",
"consentId": "ck_mobildev_0001",
"schemaVersion": "2.0",
"uiVersion": "2.4",
"legalVersion": "1.0",
"contentVersion": "2",
"contentMode": "sample",
"generatedAt": "2026-09-18T10:20:00Z",
"token": "cfg_t_8a3f5c2d1e0b",
"tokenExpiresIn": 300,
"decision": {
"updateRequired": true,
"retriggerRequired": false,
"showConsentOnLaunch": true,
"reasons": ["FIRST_RUN", "NO_CACHED_CONFIG"]
}
}

Bu örneğin aynısı ayrıca [00-auth.response.json](./00-auth.response.json) dosyasında yer alır.


6. Retrigger / Karar Matrisi

Sunucu, cihazdaki localState versiyonlarını remote versiyonlarla karşılaştırarak karar üretir. Retrigger, yalnızca onay zaten varken içerik/majör şema değişirse veya zaman interval'ı aşılır tetiklenir; uiVersion yalnız değişimi reprompt üretmez.

Cihaz durumuRemote durumuupdateRequiredretriggerRequiredshowConsentOnLaunchreasons
Hiç onay yok, cache boşherhangitruefalsetrueFIRST_RUN, NO_CACHED_CONFIG
İlk açılış, cache var ama versiyonlar eskiremote yenisitruefalsetrueFIRST_RUN, UI_UPDATED / CONTENT_UPDATED
Onay var, cihaz == remoteeşitfalsefalsefalseNO_CHANGE
Onay var, contentVersion/legalVersion arttıremote yenisitruetruetrueCONTENT_UPDATED / LEGAL_UPDATED
Onay var, schemaVersion major arttımajor bumptruetruetrueMAJOR_SCHEMA_CHANGE
Onay var, yalnız uiVersion arttıremote yenisitruefalsefalseUI_UPDATED
interval tanımlı ve lastShownAt aşıyorfalsetruetrueINTERVAL_RETRIGGER
Token süresi dolmuş, yeni AUTHtruefalseTOKEN_EXPIRED

Retrigger tetikleyicileri (config behavior.retrigger üzerinden ayarlanır):

TetikleyiciConfig alanıEtkiReprompt üretir mi?
İçerik değişikliğionConfigChange + contentVersion/legalVersion bumpOnay ekranı yeniden sorulurEvet
Majör şema değişikliğionMajorChange + schemaVersion majorOnay ekranı yeniden sorulurEvet
Zaman aralığıinterval + lastShownAtInterval aşıldıysa periyodik repromptEvet
Görsel değişiklikuiVersion bumpYalnız tema/banner yenilenirHayır

Detayda bu tetikleyiciler config'in behavior.retrigger bloğunda tanımlanır (onConfigChange / onMajorChange / interval). Müşteri, reprompt davranışını bu flag'lerle ayarlar (örn. interval: "180d" → 180 günde bir tekrar sor).


7. Hata Kodları

Hatalarda ortak gövde döner: { success:false, code, message, retryable, requestId }. message insan-okunur teşhis metnidir; UI'da gösterilmez (kullanıcıya gösterilecek metin config'in localization bloğundan gelir, ör. error_state).

codeHTTPretryableAçıklama / SDK müdahalesi
OK200Başarılı.
INVALID_API_KEY401HayırapiKey geçersiz/bilinmiyor → kendi Console'unda anahtarı kontrol et.
SIGNATURE_MISMATCH401HayırHMAC imza doğrulanamadı (secret/anahtar tutarsızlık) → imza girdisi + secret kontrolü.
REPLAY_DETECTED401HayırNonce tekrar kullanıldı veya timestamp replay penceresi dışı → cihaz saati + nonce üretimi.
PACKAGE_MISMATCH403HayırapiKey bu packageName'e tanımlı değil → Console'da uygulama/anahtar eşleşmesi.
CONSENT_NOT_FOUND404HayırconsentId kaydı yok → consentId değeri doğrulanmalı.
VALIDATION_ERROR400HayırGövde şemayı karşılamıyor (zorunlu eksik/tip/enum hatası) → detail[] alan hatalarını düzelt.
CLOCK_DRIFT400EvetCihaz saati sunucudan kabul edilemez ölçüde sapmış → NTP ile ayarla.
RATE_LIMITED429EvetHız sınırı aşıldı → Retry-After (sn) kadar bekle, yeniden dene.
SERVER_ERROR500EvetSunucu iç hata → önbellek config kullanılır, arka planda yeniden denenebilir.

retryable semantiği: false → aynı istekle tekrar denemek işe yaramaz; farklı müdahale gerekir. true → daha sonra yeniden denenebilir.


8. Offline Davranışı (KRİTİK)

Onay deneyimi sessizce bozulmamalı. Bağlantı yoksa bile kullanıcı onay akışını yaşar.

  1. AUTH, timeout (15 sn) veya hata ile başarısız olursa → SDK, son bilinen önbellek config'i + onay durumunu kullanmaya devam eder.
  2. Bağlantı gelince arka planda AUTH yeniden denenebilir; decision.updateRequired === true ise config yenileme tetiklenir.
  3. Hiç önbellek yoksa (ilk kurulum + çevrimdışı) → SDK'ya dahil edilen (bundled) varsayılan config ile onay akışı çalışır; kullanıcı boş ekranda bırakılmaz.
  4. Tüm çevrimdışı denemeler exponential backoff ile sınırlıdır; sonsuz döngü üretilmez.

9. Developer Notları

  1. AUTH hafif kalmalıdır. Her açılışta yalnız versiyon + token + decision döner. Tam config, decision.updateRequired === true olduğunda 01 · GET /config ile çekilir — asla AUTH yanıtının içine gömülmez.
  2. Token = oturum kimliği. tokenExpiresIn penceresi boyunca hem config okuması (tüketmez) hem onay kaydı (tüketir) için geçerlidir. Pencere dolunca veya oturum kapanınca yeniden AUTH yapılır. Token, bağlı olduğu consentId'e bağlıdır; başka consentId ile kullanılamaz.
  3. Versiyon modeli üç seviyeli ve bağımsızdır. İçerik veya majör şema değişimi → reprompt; yalnız görsel değişimi → reprompt yok, sadece görsel yenileme.
  4. localState geri beslemedir. SDK bunu cihazda önbelleğe alır ve her AUTH'ında gönderir; ilk çalıştırmada null/boş bırakılır. Doğru retrigger kararı bu bloğun doluluğuna bağlıdır.
  5. consent haritasının anahtarları groupId'lerdir. Değerler yalnız granted/denied. essential grubu her zaman granted'tir (kilitli) → security_storage asla denied yapılmaz. GTM/etiketlere dağıtım (groupId → consentKeys) SDK tarafında yapılır (02 adımında).