İçeriğe geç
GlobalTrustIDdocs

Go

Dış bağımlılığı olmayan Go istemcisi — OAuth ile giriş, QR ile kimlik doğrulama ve webhook imzası.

go-gti, GlobalTrustID'nin resmî Go istemcisi. Üç işi yapar: OAuth ile giriş, QR ile kimlik doğrulama, webhook imzasının doğrulanması.

Terminal
go get github.com/GlobalTrustID/go-gti

Dış bağımlılığı yok — yalnızca standart kütüphane. Her ağ çağrısı context.Context alıyor, hatalar errors.Is / errors.As ile ayırt edilebiliyor.

Hızlı bakış#

Go
import gti "github.com/GlobalTrustID/go-gti"

client, _ := gti.New(gti.Config{
    ClientID:    "gtid_...",
    RedirectURI: "https://siteniz.com/gti/callback",
})

// Yönlendirme
login, _ := client.BeginLogin(gti.ScopeOpenID)
session.Put("gti_state", login.State)
session.Put("gti_verifier", login.Verifier)
http.Redirect(w, r, login.URL, http.StatusFound)

// Callback
tokens, err := client.CompleteLogin(r.Context(), r.URL.Query(),
    session.Get("gti_state"), session.Get("gti_verifier"))
user, _ := client.FetchUserInfo(r.Context(), tokens.AccessToken)

Oturum saklama neden sizde#

Paket State ve Verifier'ı sizin adınıza saklamıyor: Go'da oturum yönetimi çerçeveye göre değişiyor (çerez, Redis, veritabanı) ve bir soyutlama uydurmak her kurulumda yanlış olurdu.

Buna karşılık CompleteLogin State'i sabit zamanlı karşılaştırıyor ve boş bir beklenen değeri reddediyor — oturumdan okunamamış bir state'i sessizce geçirmek CSRF korumasını tamamen kaldırırdı.

İki ayrı kimlik bilgisi#

APIKey ile ClientSecret aynı şey değildir ve karıştırılmaları çalışmayan entegrasyonların en sık sebebi:

Nereden alınırNe için
ClientID + ClientSecretPanel → Entegrasyonlar → OAuth UygulamalarıGiriş
APIKey (sk_live_...)Panel → API KeysKimlik doğrulama oturumları

Public istemci kullanıyorsanız ClientSecret alanını boş bırakın — akışı PKCE korur.

Kimlik doğrulama (QR)#

Go
client, _ := gti.New(gti.Config{APIKey: "sk_live_..."})

session, err := client.CreateSession(ctx, []string{
    "identity.first_name", "identity.national_id",
}, "")

fmt.Fprintf(w, `<img src="%s">`, client.QRURL(session.SessionID))

// ...kullanıcı onayladıktan sonra
result, _ := client.FetchSession(ctx, session.SessionID)
if result.Approved() && result.IdentityVerified() {
    ad := result.Identity["identity.first_name"]
}

IdentityVerified() yalnızca çipten okunabilen alanlara bakar: ad ve e-posta kullanıcının kendi yazdığı profilden de gelebilir, kimlik numarası gelemez.

Webhook#

Go
body, _ := io.ReadAll(io.LimitReader(r.Body, 1<<20))

if err := client.VerifyWebhookRequest(r, body, gti.DefaultWebhookTolerance); err != nil {
    w.WriteHeader(http.StatusUnauthorized)
    return
}

Ham gövdeyi doğrulayın: JSON'a çevirip yeniden kodlarsanız boşluk ve anahtar sırası değişir, imza tutmaz. Zaman damgası imzanın içinde olduğu için eski bir teslimatın yeniden gönderilmesi de tutmaz.

Hata yönetimi#

Go
switch {
case errors.Is(err, gti.ErrDenied):        // kullanıcı vazgeçti — hata değil
case errors.Is(err, gti.ErrStateMismatch): // CSRF şüphesi, akışı durdurun
case errors.Is(err, gti.ErrConfig):        // eksik yapılandırma
case errors.Is(err, gti.ErrTransport):     // ağ — yeniden denemek mantıklı
}

ErrTransport ile API hatası bilerek ayrı: birincisi bizim ulaşamamamız, ikincisi sunucunun "hayır" demesi ve yeniden denemek aynı cevabı verir.

Dikkat: iki scope henüz istenmemeli#

address ve identity.passport_number keşif belgesinde görünüyor ama mobil uygulama bugün ikisini de dolduramıyor. Onay için istenen alanların tamamının dolu olması gerektiğinden bunları istemek oturumu onaylanamaz hâle getirir.

Örnekler#

Çalışan üç örnek depoda: examples/login, examples/verify, examples/webhook.

Terminal
GTI_CLIENT_ID=gtid_... go run ./examples/login