Google ile giriş
Google ile giriş, oyuncunun tek tıkla web üzerinden girmesini sağlar. Bu sayfa akışın iki adımını (başlatma ve tamamlama), callback sayfanızın ne yapması gerektiğini, mevcut e-posta hesabına otomatik bağlanma kuralını ve SDK’sı olmayan yerel platform kanıtlarının HTTP sözleşmesini anlatır.
Not
Web için SDK yardımcıları bugün yalnız Google içindir. Sunucuda Apple form callback’i ve genel bir sağlayıcı kaydı da bulunur, ancak onlar için SDK yardımcısı ve bu belgede ayrıntı yoktur.
Ön koşul: sağlayıcıyı yapılandırın
Google yalnız yapılandırılmış ortamlarda çalışır. Operatör (panelde süper yönetici) Oyun ayarları › Giriş yöntemleri › Google › OAuth bilgilerini düzenle ekranına Google istemci kimliğini, istemci sırrını ve yönlendirme tabanını girer; sır yalnız yazılır, bir daha okunamaz. Yapılandırılmamışsa GET /v1/auth/oauth/providers boş liste döner ve başlatma isteği 403 alır.
Google Cloud konsolundaki Authorized redirect URI, sunucunun kullandığı redirect_uri ile birebir aynı olmalıdır: <yönlendirme tabanı>/google. Örneğin taban https://oyun.example.com/auth/callback ise Google’a https://oyun.example.com/auth/callback/google kaydedilir. Bu adres, sizin oyun sayfanızdır (aşağıdaki callback sayfası). Oyuncu Google’dan oraya code ve state ile döner. Tabanın kendisi /google ile bitmemelidir: https://oyun.example.com/auth/callback/google yazılırsa sunucu …/google/google üretir (Google redirect_uri_mismatch verir); panel ve API bu değeri düzeltilmiş örnekle reddeder. Yapılandırma ayrıntıları operatöre aittir; panel yardımı: Giriş yöntemleri.
Akış
- Oyun sayfası
POST /v1/auth/sign-in/oauth/googleile{url, state}alır ve oyuncuyuurl’ye yönlendirir. - Oyuncu Google’da onay verir; Google oyuncuyu
<yönlendirme tabanı>/google?code=…&state=…adresine döndürür. - Callback sayfası
GET /v1/auth/callback/google?code=…&state=…çağrısıyla oturumu tamamlar. Yanıt ortak giriş zarfıdır ve oturum çerezlerini yazar.
1. Başlatma
POST /v1/auth/sign-in/oauth/google
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"callback_url":"https://oyun.example.com/auth/callback/google"}
{"url":"https://accounts.google.com/o/oauth2/v2/auth?client_id=…&state=…&code_challenge=…","state":"<64 hex>"}
urlPKCE (code_challenge),stateve OIDCnoncetaşır;state10 dakika geçerlidir.callback_urlzorunludur (boşsa400), ancak yönlendirmeyi belirlemez: Google’a gidenredirect_urisunucuda yapılandırılan tabandan gelir. Adresi oyun sayfanızla tutarlı verin.403: sağlayıcı bilinmiyor, yapılandırılmamış ya da devre dışı.429: IP başına 30 / 60 sn.
2. Tamamlama
GET /v1/auth/callback/google?code=<code>&state=<state>
x-crx-env: <ortam-kimliği>
cookie: <varsa oturum çerezi>
Yanıt 200 ve giriş zarfı + çerezler. Tarayıcıda fetch(..., { credentials: "include" }) kullanın; çağrı ya API ile aynı origin’e gider ya da oyunun alan adı ortamın alan adı listesindeyse doğrudan Open Play adresine (CORS; bkz. Mimari ve barındırma). GET olduğu için CSRF belirteci istemez.
| Durum | Anlamı |
|---|---|
403 | state yok/tüketilmiş/süresi dolmuş, sağlayıcı reddi ya da imza/nonce hatası; bağlama niyetinde oturumsuz ya da başka oyuncunun oturumu. Ayrım sızdırılmaz |
409 | already exists: account_already_linked: Google kimliği başka bir oyuncuya bağlı; birleştirme yoktur |
422 | unprocessable: provider_already_linked: oyuncuda bu sağlayıcı zaten bağlı |
429 | Callback sınırı: IP başına 60 / 60 sn |
code ve state tek kullanımlıktır; callback’i ikinci kez çağırmayın.
TypeScript SDK
SDK state’i sizin yerinize tarayıcıya bağlar: başlatmada sessionStorage’a (crx-oauth-pending:v1) {state, provider, intent, startedAt} yazar, tamamlamada aynı sekmede denetler. Kayıt yoksa, 10 dakikadan eskiyse, bozuksa ya da sağlayıcı/state uyuşmuyorsa ağ isteği hiç gönderilmez ve oturum durumu değişmez; CrxError kodu OAuthBindingCode.Missing (yok/süresi dolmuş/bozuk) ya da OAuthBindingCode.Mismatch (başka tarayıcı/sekme) olur. Bu, başkasının callback bağlantısıyla oturum devralmayı engeller.
import { CrxError, OAuthBindingCode, type PlayerClient } from "@ferdiunal/open-play-ts";
// Google'ın kullanıcıyı döndürdüğü sayfa: sunucuda yapılandırılan yönlendirme tabanı + "/google" ile aynı yol olmalıdır
// (örn. taban https://oyun.example.com/auth/callback ise sayfa https://oyun.example.com/auth/callback/google).
const CALLBACK_PATH = "/auth/callback/google";
/** 1. adım: Google'a yönlendirin. State'i saklamanız gerekmez; SDK onu bu sekmeye bağlar (sessionStorage). */
export async function beginGoogleSignIn(client: PlayerClient): Promise<void> {
const callbackUrl = `${window.location.origin}${CALLBACK_PATH}`;
const { url } = await client.session.startGoogleOAuth(callbackUrl);
window.location.assign(url);
}
/** Misafir (ya da kayıtlı) oyuncunun hesabına Google kimliğini bağlar; tamamlama aynı callback sayfasında yapılır. */
export async function beginGoogleLink(client: PlayerClient): Promise<void> {
const callbackUrl = `${window.location.origin}${CALLBACK_PATH}`;
const { url } = await client.session.linkOAuth("google", callbackUrl);
window.location.assign(url);
}
/** 2. adım: Google'ın döndüğü sayfada (`/auth/callback/google`) code ve state ile oturumu tamamlayın. */
export async function finishGoogleSignIn(client: PlayerClient): Promise<string> {
const params = new URL(window.location.href).searchParams;
const code = params.get("code");
const state = params.get("state");
history.replaceState(null, "", window.location.pathname); // code ve state adres çubuğunda kalmasın
if (code === null || state === null) throw new Error("Callback adresinde code ya da state yok.");
try {
const session = await client.session.completeGoogleOAuth(code, state);
return session.playerId;
} catch (error) {
if (error instanceof CrxError && error.code === OAuthBindingCode.Mismatch) throw new Error("Giriş başka bir tarayıcıda başlatılmış.");
if (error instanceof CrxError && error.code === OAuthBindingCode.Missing) throw new Error("Giriş süresi dolmuş; yeniden başlatın.");
throw error;
}
}
/** Hesabıma bağlı sağlayıcı kimlikleri (sağlayıcı hesap kimliği ve e-posta dönmez). */
export async function linkedProviders(client: PlayerClient): Promise<string[]> {
const result = await client.session.listIdentities();
return result.identities.map((identity) => identity.provider);
}
startGoogleOAuth(callbackUrl)=startOAuth('google', callbackUrl);completeGoogleOAuth(code, state)=completeOAuth({ provider, code, state }).linkOAuth(provider, callbackUrl)bağlama akışını başlatır (aşağıya bakın); tamamlama yinecompleteOAuthiledir.listIdentities()bağlı kimlikleri verir.- Callback sayfasında
codevestate’i hemen adres çubuğundan kaldırın (history.replaceState). - Unity SDK’sında OAuth yardımcısı yoktur.
Uyarı
TypeScript SDK’sında
startIdentityTransferadlı bir yöntem görünür; sunucuda karşılığı yoktur (operatör destekli kimlik devri iptal edilmiştir). Kullanmayın.
Misafir ilerlemesini Google’a bağlama
Oturum açık bir oyuncu (misafir ya da kayıtlı) için linkOAuth kullanılır: POST /v1/auth/link/{provider} oturum ister ve {url, state} döner; tamamlama aynı callback ucudur, ancak callback isteği başlatan oyuncunun oturumuyla gelmelidir (çerez ya da Bearer), aksi halde 403.
- Oyuncu misafirse bağlama bir terfidir: aynı
player.id,is_guest: false, misafir sırrı emekliye ayrılır ve yeni oturum açılır. Misafirin kendi koyduğu ad korunur; ad hâlâ varsayılanGuestise Google adı uygulanır. - Oyuncu kayıtlıysa yalnızca yeni kimlik eklenir; adına dokunulmaz.
- Sağlayıcı başına tek kimlik vardır (
422 provider_already_linked). - Google kimliği başka bir oyuncuya bağlıysa
409 account_already_linkeddöner; ilerlemeler birleştirilmez.
Ayrıntılar: Hesap bağlama.
E-postayla otomatik bağlanma
Google ile yeni bir kimlikle giren oyuncunun e-postası, mevcut bir e-posta/parola hesabıyla eşleşiyorsa Google kimliği o hesaba otomatik bağlanır ve oyuncu o hesaba girer. Kuralın koşulları:
- E-posta Google tarafından doğrulanmış olmalıdır ve Google bu e-postanın güncel sahipliğine kefil olmalıdır: alan adı
gmail.com/googlemail.comya da imzalı ID token’ınhdtalebi e-postanın alan adına eşit (Google Workspace). Üçüncü taraf bir adresteemail_verifiedtek başına yetmez. - Eşleşme oyuncunun profil e-postasıyla (
players.email) yapılır; parolaya, mevcut oturumlara ya da profil e-postasına dokunulmaz. - Eşleşen hesap banlıysa bağ yazılmaz ve giriş reddedilir.
- Eşleşen hesapta zaten başka bir Google kimliği varsa otomatik bağlanma yapılmaz; yeni bir oyuncu açılır.
- Kayıt kapalı olsa da çalışır (yeni kayıt değildir).
- Bu davranışı kapatan bir ayar yoktur; yerel (native) ID-token yolunda bu bağlama uygulanmaz.
- Misafirin Google’a bağlanmasında (terfi) Google e-postası başka bir oyuncunun e-postasıyla eşleşiyorsa birleştirme yapılmaz;
409 account_already_linkeddöner.
Hesapta saklananlar: Google kimliği yalnız (ortam, sağlayıcı, sub) ile tanınır. Google’ın ad, doğrulanmış e-posta, dil ve profil görseli adresi kimliğe yazılabilir; sağlayıcının erişim ve yenileme belirteçleri saklanmaz. Bu bilgiler yalnız operatör panelinde görünür.
Yerel platform kanıtları
Mobil yerel girişler için tek bir uç vardır; SDK yardımcısı henüz yoktur (TypeScript’te ve Unity’de yok). Uç, ortak CSRF kurallarına tabidir ve çerez yazmaz: yanıtı Bearer olarak kullanın.
POST /v1/auth/native/{provider}
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
provider | Gövde |
|---|---|
apple, google | {"id_token":"<OIDC ID token>","nonce":"<ham nonce>"} |
gamecenter | {"proof":{"player_id":"…","bundle_id":"…","public_key_url":"…","signature_b64":"…","salt_b64":"…","timestamp_ms":1700000000000,"game_player_id":"…"}} |
playgames | {"proof":{"server_auth_code":"…","application_id":"…"}} |
200 ve {player, tokens, is_new_player} (çerez yok). 400: sağlayıcı yerel girişe uygun değil ya da ortamda kayıtlı değil, zarf biçimi bozuk. 403: kanıt reddedildi (imza, sertifika zinciri, paket kimliği, zaman aşımı, nonce gibi hiçbir ayrım sızdırılmaz). Kullanım için ortamda ilgili platformun yapılandırılmış olması gerekir.
Not
Yerel kanıt yolu e-postayla otomatik bağlanma uygulamaz; aynı kişi yerel ve web yoluyla ayrı oyunculara bölünebilir.