globaltrustid / php
GlobalTrustID PHP istemcisi — OAuth/OpenID Connect ile giriş, QR ile kimlik doğrulama ve webhook imza doğrulaması.
Requires
- php: >=5.6.0
- ext-curl: *
- ext-json: *
- ext-openssl: *
Requires (Dev)
- phpunit/phpunit: ^9.6 || ^8.5 || ^7.5 || ^5.7
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
GlobalTrustID'nin resmî PHP istemcisi. Üç işi yapar:
- "GlobalTrustID ile giriş" — OAuth 2.0 / OpenID Connect, PKCE (S256) ile.
- Kimlik doğrulama — QR oluşturur, kullanıcı telefonuyla onaylar, sonucu okursunuz.
- Webhook doğrulama — gelen bildirimin gerçekten bizden geldiğini kanıtlar.
use GlobalTrustID\Client; $gti = new Client(['client_id' => 'gtid_...', 'redirect_uri' => 'https://siteniz.com/callback']); header('Location: ' . $gti->loginUrl()); // 1. kullanıcıyı yolla $user = $gti->handleCallback(); // 2. callback'te profili al echo $user['sub'];
- Bağımlılık yok — yalnızca
curl,jsonveopenssleklentileri. - PHP 5.6'dan 8.x'e kadar aynı kod. Eski paylaşımlı hostinglerde de çalışır.
- Laravel ve CodeIgniter için hazır entegrasyon.
İçindekiler
- Kurulum
- İki ayrı kimlik bilgisi
- 1. GlobalTrustID ile giriş
- 2. Kimlik doğrulama (QR)
- 3. Webhook
- Laravel
- CodeIgniter 4
- Alanlar (scope)
- API
- Composer olmadan
- Sık karşılaşılanlar
Kurulum
composer require globaltrustid/php
Gereken: PHP 5.6+, ext-curl, ext-json, ext-openssl.
İki ayrı kimlik bilgisi
Bu, çalışmayan entegrasyonların en sık sebebi. api_key ile client_secret
aynı şey değildir:
| Nereden alınır | Ne için | |
|---|---|---|
client_id + client_secret |
Panel → Entegrasyonlar → OAuth Uygulamaları | Giriş (OAuth) |
api_key (sk_live_...) |
Panel → API Keys | Kimlik doğrulama oturumları |
sk_live_... bir API anahtarıdır ve api_key alanına yazılır — OAuth
istemcisinin sırrı değildir. Yalnızca giriş yapacaksanız api_key'e,
yalnızca kimlik doğrulaması yapacaksanız client_id/client_secret'a
ihtiyacınız yok.
Public istemci kullanıyorsanız
client_secretyazmayın. Tarayıcı ya da mobil uygulama sır saklayamaz; akışı PKCE korur. Panelde "Public istemci" kutusu bunun için.
1. GlobalTrustID ile giriş
require __DIR__ . '/vendor/autoload.php'; use GlobalTrustID\Client; use GlobalTrustID\Exception as GtiException; $gti = new Client([ 'client_id' => 'gtid_...', 'redirect_uri' => 'https://siteniz.com/gti-callback.php', 'client_secret' => '...', // yalnızca confidential istemcide ]);
Yönlendirme sayfası:
// SCOPE_OPENID = yalnızca giriş; hiçbir kişisel veri paylaşılmaz. header('Location: ' . $gti->loginUrl(Client::SCOPE_OPENID)); exit;
Callback sayfası:
try { $user = $gti->handleCallback(); } catch (GtiException $e) { http_response_code(400); exit($e->getMessage()); } // 'sub' kullanıcının DEĞİŞMEYEN kimliği. Kendi tablonuzda bunu saklayın, // e-postayı değil — e-posta değişebilir, sub değişmez. $gtiSub = $user['sub'];
handleCallback() PKCE verifier'ını ve state'i depodan okur, state'i
sabit zamanlı karşılaştırır (CSRF), kodu token'a çevirir ve profili döner.
Token'lar $user['_tokens'] altındadır.
loginUrl()çağrılmadan önce oturumun başlamış olması gerekir. Varsayılan depo$_SESSIONkullanır ve gerekirsesession_start()'ı kendisi çağırır.
2. Kimlik doğrulama (QR)
Kullanıcının kimliğini doğrulatmak için — giriş değil.
$gti = new Client(['api_key' => 'sk_live_...']); $session = $gti->verify(['identity.first_name', 'identity.last_name', 'identity.national_id']); echo '<img src="' . htmlspecialchars($gti->qrUrl($session['session_id'])) . '">';
Kullanıcı QR'ı GlobalTrustID uygulamasıyla okutup onayladıktan sonra:
$result = $gti->result($session['session_id']); if ($result['status'] === 'approved') { $ad = $result['identity']['identity.first_name']; }
"Bu kişi kimliğini gerçekten doğruladı mı?"
if ($gti->isIdentityVerified($result)) { // Kimlik BELGESİ NFC ile okundu. }
Ad ve e-posta kullanıcının kendi yazdığı profilden de gelebilir; kimlik numarası ve belge numarası gelemez — onlar yalnızca çipten çıkar. Bu metot tam olarak buna bakar.
Sonuçları beklemek yerine size gönderilmesini isterseniz verify()'a bir
webhook adresi verin.
3. Webhook
$gti = new Client(['webhook_secret' => 'whsec_...']); // HAM gövdeyi ÖNCE okuyun. $raw = file_get_contents('php://input'); if (!$gti->verifyWebhook($raw)) { http_response_code(401); exit; } $payload = json_decode($raw, true);
Bu adımı atlamayın. Webhook adresiniz herkese açıktır; imzayı
doğrulamadan gövdeye güvenirseniz, size sahte bir approved gönderen herkes
kimlik doğrulamasını atlatmış olur.
Gövdeyi JSON'a çevirip yeniden kodlarsanız boşluk ve anahtar sırası değişir, imza tutmaz. Ham baytları doğrulayın.
verifyWebhook() ayrıca zaman damgasına bakar: imza geçerli olsa bile 5
dakikadan eski bir istek reddedilir (replay koruması). Kuyruğa alınmış
webhook'ları sonradan işliyorsanız $tolerance parametresini 0 yapın.
Laravel
composer require globaltrustid/php
Paket auto-discovery ile bulunur; config/app.php'ye bir şey eklemeniz
gerekmez.
GTI_CLIENT_ID=gtid_... GTI_REDIRECT_URI=https://siteniz.com/gti/callback GTI_API_KEY=sk_live_... GTI_WEBHOOK_SECRET=whsec_...
class GtiController extends Controller { public function __construct(private \GlobalTrustID\Client $gti) {} public function redirect() { return redirect()->away($this->gti->loginUrl()); } public function callback(Request $request) { $profile = $this->gti->handleCallback($request->query()); // ... } }
İstemciyi kapsayıcıdan alın, elle new Client(...) yazmayın: sağlayıcı
onu Laravel oturumuyla kuruyor. Elle kurarsanız PKCE verifier'ı $_SESSION'a
yazılır ve Laravel oturumu Redis/veritabanı sürücüsündeyse callback'te geri
okunamaz.
Facade da var:
use GlobalTrustID\Laravel\GlobalTrustIDFacade as GlobalTrustID; return redirect()->away(GlobalTrustID::loginUrl(['email']));
Tam örnek: examples/laravel/.
CodeIgniter 4
composer require globaltrustid/php
CI4'te kendini bağlayan bir sağlayıcı yok; istemciyi bir Services girdisiyle
kurarsınız. Hazır dosyalar: examples/codeigniter/.
$gti = service('gti'); return $this->response->redirect($gti->loginUrl());
Alanlar (scope)
Kullanıcı onay ekranında tam olarak ne istediğinizi görür. İstemediğiniz hiçbir alan size gelmez.
| Scope | Ne döner |
|---|---|
openid |
Yalnızca giriş — hiçbir kişisel veri paylaşılmaz |
identity.first_name / identity.last_name |
Ad / soyad |
identity.birth_date |
Doğum tarihi |
identity.gender |
Cinsiyet |
identity.national_id |
TC kimlik numarası — yalnızca çipten |
identity.document_number |
Belge numarası — yalnızca çipten |
identity.nationality |
Uyruk — yalnızca çipten |
age.over_18 |
Doğum tarihi olmadan yalnızca "true" / "false" |
email |
E-posta |
phone |
Telefon |
avatar |
Profil görselinin adresi |
"Yalnızca çipten" işaretli alanlar kullanıcının profilinden doldurulamaz;
istemek, NFC ile belge okumasının yapılmış olmasını şart koşar. Listeyi kodda
Client::chipOnlyScopes() ile alabilirsiniz.
age.over_18, yaş sınırı denetlemek için doğum tarihi istemenin yerine geçer:
kullanıcı doğum gününü paylaşmadan reşit olduğunu kanıtlar.
addressveidentity.passport_numberHENÜZ İSTEMEYİN. Sunucunun keşif belgesinde (/.well-known/openid-configuration) görünüyorlar ama mobil uygulama bugün ikisini de dolduramıyor — kimlik cüzdanı özelliğiyle gelecekler. Onay için istenen ALANLARIN TAMAMININ dolu olması gerektiğinden, bu ikisini istemek oturumu onaylanamaz hâle getirir: kullanıcı "Onayla"ya basamaz ve sebebini anlamaz.
API
new Client(array $config)
| Anahtar | Açıklama |
|---|---|
client_id |
OAuth uygulamanız (gtid_...) |
client_secret |
Yalnızca confidential istemcide |
redirect_uri |
Kayıtlı dönüş adresiniz (tam eşleşme) |
api_key |
sk_live_... — kimlik doğrulama oturumları için |
webhook_secret |
Webhook imzasını doğrulamak için |
api_base |
Varsayılan https://api.globaltrust.id |
issuer |
Varsayılan https://globaltrust.id |
timeout |
Saniye, varsayılan 15 |
verify_ssl |
Varsayılan true. Kapatmayın. |
store |
StoreInterface — PKCE verifier ve state'in yazılacağı yer |
OAuth
loginUrl($scope = 'openid'): stringhandleCallback($query = null): arrayexchangeCode($code, $codeVerifier): arrayrefresh($refreshToken): arrayuserInfo($accessToken): array
Kimlik doğrulama
verify($scope, $webhookUrl = ''): arrayresult($sessionId): arrayisApproved($sessionId): boolisIdentityVerified($result): boolqrUrl($sessionId): stringClient::chipOnlyScopes(): array
Webhook
verifyWebhook($rawBody, $signature = null, $timestamp = null, $tolerance = 300): bool
Hatalar GlobalTrustID\Exception olarak fırlatılır.
Composer olmadan
Eski bir kurulumda Composer yoksa dosyaları doğrudan dahil edebilirsiniz:
require_once 'src/Exception.php'; require_once 'src/Store/StoreInterface.php'; require_once 'src/Store/SessionStore.php'; require_once 'src/Client.php'; $gti = new GlobalTrustID\Client([...]);
Sık karşılaşılanlar
"client_secret gerekli" diyor ama public istemcim var.
client_secret alanını hiç yazmayın. Boş bir dize göndermek sunucuya "sırrım
var ama boş" demektir.
"state eşleşmedi (CSRF şüphesi)". Giriş başka bir tarayıcıda başlatılmış, oturum süresi dolmuş ya da oturum deposu iki istek arasında paylaşılmıyor. Laravel/CI4 kullanıyorsanız oturum deposunu doğru bağladığınızdan emin olun.
"oturum bulunamadı".
loginUrl() ile handleCallback() farklı oturumlarda çalışıyor. Yük
dengeleyici arkasındaysanız oturumların sunucular arasında paylaşıldığından
emin olun.
Webhook imzası tutmuyor.
Ham gövdeyi doğruluyor musunuz? $_POST, $request->all() ya da
getJSON() gövdeyi çözüp yeniden kodlar ve imza artık tutmaz.
identity boş geliyor.
Sonuçlar kalıcı saklanmaz, kısa süre sonra silinir. Onay gelir gelmez okuyun
ya da webhook kullanın.
Destek
- Sorun bildirimi: GitHub Issues
- Dokümantasyon: docs.globaltrust.id
Lisans
MIT — bkz. LICENSE.