Studio Atelico / Bobium Brawlers

iOS Game Auth Playbook:
Godot + Supabase

Anonymous-first authentication with silent Game Center, cascading to Apple/Google/Email. Technical architecture, funnel strategy, and implementation guide for a mid-casual iOS game with a 2GB download.

Supabase Auth Godot 4.x / GDExtension iOS-only / Game Center
Bottom line

Anonymous-first + silent Game Center is the optimal flow. Supabase creates an anonymous session at launch (zero UI). Game Center authenticates silently in the background for most iOS users. If Game Center fails, the user plays anonymously through the tutorial, then sees a "Save your progress?" prompt offering Apple/Google/Email sign-in. The anonymous Supabase user_id persists across all transitions—no data migration ever.

Game Center is not a native Supabase provider. You bridge it via a Supabase Edge Function that verifies Apple's cryptographic signature and issues a JWT. For Godot, GodotApplePlugins (SwiftGodot/GDExtension by Miguel de Icaza) provides Game Center + Sign in with Apple out of the box for Godot 4.2+.

Guide map — click to jump
Sections & key takeaways
01 Why anonymous-first: funnel principles
Takeaway
Every screen between app launch and gameplay costs ~20% of users. With a 2GB download already filtering for intent, a login wall is the worst possible next step. Let them play immediately.
Context
Industry benchmarks on login drop-off, Day 1/7/30 retention rates, and how Supercell, Marvel Snap, and Apple Arcade handle first-time onboarding for mobile games.
02 The authentication cascade
Takeaway
Two invisible phases happen at launch: we create a guest session, then silently check Game Center. Most iOS users (~70-85%) get fully authenticated with zero interaction. Everyone else gets prompted after the tutorial.
Context
The full state machine for our auth flow, from app launch through Game Center check, tutorial, and the post-tutorial 'Save your progress?' prompt with Apple/Google/Email/Skip options.
03 What Supercell actually does (and what we can learn)
Takeaway
Supercell originally used Game Center for identity, then built Supercell ID (passwordless email) for cross-platform play. Their pattern validates ours: play first, identity later, prompt based on investment level. Supercell ID is our long-term blueprint.
Context
How Clash of Clans evolved from Game Center-only auth to Supercell ID, why they made that transition, and what it means for our starting point with Game Center + Apple/Google fallbacks.
04 Account recovery and creature protection
Takeaway
Creatures are the product. If a user loses them, they lose everything personal. Upload creatures to the cloud immediately regardless of auth state. Frame sign-in around 'protect your creatures,' not 'create an account.' Re-prompt at milestones.
Context
Recovery matrix showing what happens across every combination of auth state and device change. No persistent device ID exists on iOS, so account linking is the only durable recovery mechanism.
05 The 2GB download and progressive engagement
Takeaway
Auth should take under 3 seconds from app launch to playable state. Consider shipping a ~200MB initial app with core gameplay, then streaming the remaining 1.8GB of AI models in the background via iOS On-Demand Resources.
Context
How the large download size affects funnel design, auth sequencing relative to the install, and the opportunity to use iOS background asset delivery to reduce time-to-play.
06 COPPA and younger-skewing audiences
Takeaway
Anonymous-first is inherently COPPA-friendly since we collect zero personal data at launch. Gate identity-linking behind a neutral age check (date of birth). Under-13 users stay in anonymous or Game Center-only mode. New state laws (TX, UT, LA in 2026) add requirements.
Context
How COPPA applies to a mixed-audience AI game with a younger-skewing family demographic, what data collection is restricted, and the updated federal and state regulations taking effect in 2026.
07 Implementation priority
Takeaway
P1: Guest login (launch blocker, ship the game with just this). P2: Game Center silent auth + server-side verification. P3: Apple and Google sign-in options. P4: Age gate and COPPA compliance. The server-side Game Center verification is the hardest single piece.
Context
Ordered build plan showing what to ship first, what to defer, and where the hard engineering work lives across the four priority tiers.
08 Session persistence and lifecycle ENG
Takeaway
Sessions survive everything except app deletion. Tokens are stored on the device in app storage. They never expire on their own. If the user deletes the app without linking an account, their session (and creatures) are gone forever. The token-saving code is the most critical auth code in the game.
Context
Where Supabase tokens live on disk, what happens on app close/kill/reboot/delete/offload, refresh token rotation mechanics, and what 'skip' means in the post-tutorial prompt.
09 Game Center: how it actually works ENG
Takeaway
Game Center authenticates silently on most iOS devices with zero user interaction. It uses cryptographic signatures instead of OAuth, provides no email address, and gives us a persistent player ID tied to the user's Apple ID. Xcode setup is one capability toggle.
Context
The technical mechanics of Game Center's authentication handler, its signature-based identity verification system, the available player identifiers, and Xcode configuration requirements.
10 Bridging Game Center to Supabase ENG
Takeaway
Game Center is not a built-in Supabase provider. We bridge it with a server-side Edge Function that verifies Apple's cryptographic signature and issues a Supabase session. This is custom code we have to write and is the hardest piece of the auth system.
Context
Architecture diagram and implementation details for the Supabase Edge Function that verifies Game Center signatures, creates or finds users, and returns session tokens. Includes security checklist and account-linking strategy.
11 Apple and Google sign-in providers ENG
Takeaway
Both Apple and Google are natively supported by Supabase. They attach to existing guest accounts without changing the user ID, so no data migration is needed. Apple Sign-In is mandatory per App Store rules if we offer Google. Google requires a config tweak for iOS.
Context
Technical setup for Apple and Google sign-in via Supabase, including required Xcode capabilities, dashboard configuration, and how account linking preserves the anonymous user's identity.
12 Godot plugin landscape ENG
Takeaway
GodotApplePlugins (by Miguel de Icaza) is the clear first choice for Game Center and Apple Sign-In. It's a modern Swift-based plugin for Godot 4.2+. For Supabase connectivity, the community GDScript addon handles auth, database, and storage via REST.
Context
Comparison of available Godot plugins for iOS Game Center and Apple Sign-In, the signal flow for native auth callbacks, platform guards for editor vs. on-device, and the full launch auth code sequence.
13 Xcode entitlements and capabilities ENG
Takeaway
Two toggles in Xcode (Game Center + Sign in with Apple), one plist entry for Google. That's the complete list of Xcode changes needed. Godot respects the entitlements file from the export template.
Context
Complete checklist of every Xcode capability, entitlement key, and Info.plist modification required for the full auth stack.
01

Why anonymous-first: funnel principles

The goal of any mobile game auth system is to maximize the number of users who reach gameplay while preserving the ability to identify, retain, and recover accounts. Every interaction between "app launch" and "playing the game" is a leak in the funnel. The math is unforgiving:

MetricIndustry benchmarkImplication
Login screen abandonment~20% of users1 in 5 users quit at a login wall
Form abandonment (registration)~92% of consumers have abandonedNever show a form before gameplay
Day 1 retention (iOS games)27–35%You lose 2/3 of users on Day 1
Day 7 retention10–15%Compounding loss every day
Day 30 retention3–6%Only the deeply engaged remain

Your 2GB download is the first filter. Users who completed that download are already invested—they waited, they have intent. Hitting them with a login wall at this point is the worst possible friction. The download itself is your commitment device. Auth should be invisible on first launch.

How top games handle this

Supercell (Clash of Clans, Brawl Stars): Zero login at launch. Device-bound account. Supercell ID offered later via Settings as a passwordless email code system for cross-device sync and account recovery. Supercell ID is presented as a save/sync feature, not a login gate.

Marvel Snap: Shows Guest / Google / Apple / Facebook options on the title screen, but Guest is the default and most prominent option. Account linking is prompted after the tutorial via Settings. Progress is preserved regardless of which path the user takes.

Apple Arcade titles: Game Center silently and automatically. No login screen at all. This is the gold standard for iOS.

PRINCIPLE
The pattern is universal: play first, identity later. Authentication exists to protect progress, enable cross-device play, and support social features. None of those matter in the first 60 seconds. The user's first minute should be gameplay, not forms.

Your audience: families and younger-skewing users

Parents playing with kids changes the calculus. A parent handing their phone to a child does not want that child entering an email address or Apple ID password. Game Center is perfect here because it's already authenticated at the device level—the child doesn't interact with auth at all. Anonymous mode is the fallback: no PII, no forms, no risk. This also helps with COPPA compliance (covered in Section 6).

02

The authentication cascade

The system operates in two phases. Phase 1 (launch, zero UI) creates an anonymous Supabase session and attempts silent Game Center auth. Phase 2 (post-tutorial) prompts remaining anonymous users to link an identity provider.

PHASE 1 — AUTOMATIC (ZERO UI) App Launch 1 Supabase signInAnonymously() 2 GKLocalPlayer.authenticateHandler GC OK? YES (silent) Edge Fn: link GC → Supa NO PHASE 2 — POST-TUTORIAL PROMPT 3 Tutorial / FTUE gameplay 4 "Save your progress?" Sign in with Apple Google Email Skip linkIdentity() → permanent user Playing (same user_id preserved across all states)
Fig 1. Authentication cascade state machine. Phase 1 is invisible. Phase 2 triggers only for non-Game Center users post-tutorial.
03

What Supercell actually does (and what we can learn)

Supercell's auth evolution is instructive because they went through exactly the transition you're designing for.

The history

Originally (2012-2016): Clash of Clans used Game Center on iOS and Google Play Games on Android as the sole account identity. Your village was tied to your Game Center ID. If you switched Game Center accounts, you could load a different village. This was the only recovery mechanism. If you didn't have a Game Center account or forgot which Apple ID you used, Supercell support had to manually intervene.

Supercell ID (2017+): Supercell built their own cross-platform identity system. It's a passwordless email login: enter your email, receive a 6-digit code, done. No password to remember. Once connected, Supercell ID replaces Game Center as the account identity. You can no longer load your account via Game Center after connecting. This was a deliberate choice: Supercell wanted platform-independent identity so users could move between iOS and Android.

How it works today

First launch: Zero login. You get a device-bound account immediately and start playing. No Game Center prompt, no sign-in screen, nothing. Supercell generates an internal player ID and stores the session locally.

Supercell ID prompt: After some gameplay (varies by title), a small banner or settings option encourages you to connect Supercell ID. It's not mandatory. Many players play for months without connecting. The prompt framing is about protecting your progress and playing on multiple devices, not about "creating an account."

Game Center relationship: Supercell games still integrate with Game Center for leaderboards and achievements, but Game Center is no longer used as an authentication mechanism for account recovery since Supercell ID replaced it. If you haven't connected Supercell ID and lose your device, Supercell support can sometimes recover your account using Game Center data as a secondary verification method, but it's not guaranteed.

What this means for Bobium Brawlers

LESSON
Supercell's approach validates the core strategy: play first, identity later, prompt based on investment level. They went further than you need to by building a custom identity system, but that was driven by their cross-platform requirements (iOS + Android). Since you're iOS-only, Game Center + Apple Sign-In covers the same ground without building custom infrastructure. The Supercell ID pattern maps directly to your "Save your progress?" prompt with Apple/Google/Email options.

Game Center availability on iOS

Game Center is automatically enabled on every iOS device with an Apple ID. You sign into Game Center by signing into your Apple ID, which happens during device setup. Apple aggressively auto-signs users back into Game Center even when they try to sign out (this is a consistent complaint in Apple Support forums). The practical result: the vast majority of iOS devices have Game Center active.

One indie developer reported ~59% of game launches had Game Center authenticated. However, this data is from 2020 and the measurement methodology was imprecise. The real number for modern iOS (15+) is likely higher, because Game Center is now tied to the system Apple ID and Apple makes it very difficult to permanently disable. Conservative estimate: 70-85% of your iOS users will have Game Center available at launch. The remaining 15-30% are users who have actively signed out of Game Center (rare), have restricted accounts (Family Sharing child accounts with GC disabled by parents), or are on very old iOS versions.

For the users who don't have Game Center, the cascade catches them: anonymous first, then the post-tutorial prompt for Apple/Google/Email. No user falls through every net.

04

Account recovery and creature protection

This is the core tension: creatures are the product. If a user loses their creatures, they've lost everything that makes Bobium Brawlers personal. The auth system exists primarily to prevent this.

The recovery matrix

User stateDeletes appNew phone, same Apple IDNew phone, different Apple ID
Anonymous only (no GC, no Apple, no Google) Creatures gone forever. No recovery path. Creatures gone. New anonymous account. Creatures gone.
Game Center linked Reinstall, GC auto-auths, Edge Fn finds user by teamPlayerID, session restored. Same. GC identity travels with Apple ID. Different Apple ID = different teamPlayerID. No match.
Apple Sign-In linked Reinstall, sign in with Apple, Supabase matches by Apple sub ID. Same Apple ID = same sub. Works. Different Apple ID = different sub.
Google linked Reinstall, sign in with Google, Supabase matches by Google sub. Works (Google is cross-platform). Works if same Google account.

The takeaway: Game Center is good enough for single-Apple-ID recovery (which is the vast majority of cases), but Google is the most portable option. For a family where a kid plays on Mom's phone and later gets their own device with a different Apple ID, Google is the only automatic recovery path.

Can you get a device ID instead?

No. Apple deprecated UDID in 2013 and removed identifierForVendor persistence across reinstalls in later iOS versions. identifierForVendor resets when the user deletes all apps from your developer team and reinstalls. There is no universal, persistent device identifier on iOS that survives app deletion. This is by design (privacy). The only persistent identifiers are those tied to an account: Apple ID (via Game Center or Sign in with Apple), Google account, or an email/password you store yourself.

Creature backup as an incentive

The strongest approach for your game specifically: all creatures are uploaded to Supabase Storage as soon as they're created, regardless of auth state. Anonymous users get cloud creature storage. The difference is whether they can recover access to those creatures from another device. Frame the sign-in prompt around this: "Your creatures are safe in the cloud, but only you can get them back. Link an account so you never lose them." This means even anonymous users' data is server-side, which makes manual recovery possible (support team looks up creatures by name/metadata) even if there's no automated path.

Re-prompting strategy

Don't prompt once and forget. Prompt when it matters:

TriggerMessage framing
Created 3rd creature"You've got 3 creatures now. Protect them."
Won 5th battle"Nice streak. Don't risk losing your team."
7 days of play, still anonymous"You've been playing a week. One tap to save everything."
Before any IAPGate purchases behind linked accounts. This is also COPPA-smart.
05

The 2GB download and progressive engagement

A 2GB download creates a unique funnel shape. The user has already committed significant time and bandwidth before they see your app. This changes the auth calculus:

Don't waste the investment. The user just waited for a large download. They are primed to play. Every second between "download complete" and "gameplay" is wasted goodwill. Auth must be invisible.

Consider on-demand resources. iOS supports On-Demand Resources (ODR) and Background Assets framework. If you can ship a ~200MB initial app with core gameplay, then stream the remaining ~1.8GB of AI models and assets in the background, you dramatically reduce the time-to-play. The user starts playing within a minute of tapping "Get" in the App Store while the full asset set downloads behind the scenes. This is orthogonal to auth but massively impacts the same funnel.

The auth/download sequencing: Auth should happen after the app is open and running, not during the download or install. On iOS, there is no mechanism to collect auth during download anyway—but some games attempt a "pre-register" flow via their website or social media. For your case, skip this entirely. The App Store > Download > App Launch > Anonymous Auth (instant) > Silent GC (instant) > Gameplay pipeline should take under 3 seconds from app launch to playable state.

06

COPPA and younger-skewing audiences

Your "parents playing with kids, AI-themed game" audience likely qualifies as mixed-audience or child-directed under COPPA. The key restriction: you cannot collect personal information from users under 13 without Verifiable Parental Consent (VPC). "Personal information" includes email addresses, persistent identifiers, and (under the updated rule effective April 2026) device IDs and IP addresses.

How anonymous-first helps

The anonymous-first pattern is inherently COPPA-friendly. A locally-generated anonymous UUID with no PII transmission satisfies minimal data requirements. You don't collect email, name, or any identifier until the user opts into account linking—which you can gate behind a neutral age check.

What you need to implement

Neutral age gate: Before any data collection beyond internal operations, ask for date of birth (not age directly, and never telegraph the "correct" answer). If the user is under 13, operate in zero-data mode. If 13+, proceed with standard auth flows. Place this gate before the "Save your progress?" prompt, not at app launch.

Game Center special case: Game Center's isUnderage flag is set by Apple based on the Apple ID's date of birth. If isUnderage == true, the player can still authenticate (Game Center handles parental consent at the system level), but you should restrict social features and data collection in your app.

ENFORCEMENT RISK
New App Store Accountability Acts in Texas (Jan 2026), Utah (May 2026), and Louisiana (Jul 2026) require app stores to verify ages and obtain parental consent for every minor's download and in-app purchase. Design for these constraints now rather than retrofitting later. The FTC has levied significant fines for COPPA violations in games.
07

Implementation priority

1
Supabase anonymous auth Day 1 launch blocker. signInAnonymously() on every app launch that doesn't have an existing session. This is the foundation everything else builds on. Ship the game with just this and you have a functional auth system.
2
Game Center integration Integrate GodotApplePlugins, write the Supabase Edge Function for GC signature verification, and wire up silent auth at launch. This covers the majority of iOS users with zero friction. The Edge Function is the hardest piece—budget time for the crypto verification.
3
Sign in with Apple + Google Add as linkIdentity() options in the post-tutorial "Save your progress?" prompt. Apple is mandatory once Google is present. Both use native signInWithIdToken()—straightforward Supabase integration.
4
Age gate + COPPA compliance Implement before any identity-linking prompts. Neutral date-of-birth gate. Under-13 users stay in anonymous/GC-only mode. Document privacy practices per FTC requirements.
KEY INSIGHT
Game Center's silent auth + Supabase anonymous auth creates a near-zero-friction authenticated state for most iOS users on first launch. No user interaction required. The user gets a playable anonymous session instantly, and if Game Center is available (it usually is), their identity is cryptographically verified and linked within seconds—all invisible. The "Save your progress?" prompt becomes a safety net, not the primary auth path.
Engineering deep dives
The following sections contain implementation details. Click any section to expand.
08

Session persistence and lifecycle

ENG-CENTRIC
Show implementation details

This is the most important section for understanding what actually happens on the device and server. Where does the session live? What happens when you close the app? What happens when you delete the app?

Where the session is stored

When Supabase's signInAnonymously() succeeds, it creates two things: a server-side record in auth.users and auth.sessions (on Supabase's Postgres), and a client-side token pair (access token JWT + refresh token string). The client library stores this token pair in whatever storage backend you configure. In a browser, that's localStorage by default. In Godot, you're using the supabase-community/godot-engine.supabase addon, which stores the tokens however you implement the storage adapter. For a mobile game, you should write the tokens to a file in the app's sandboxed data directory (e.g., user://auth_session.json in Godot's user:// path).

App lifecycle: close, reopen, kill, reboot

EventWhat happens to sessionUser impact
App backgrounded / closed Tokens remain in user:// storage. Nothing changes. None. Seamless resume.
App killed from task switcher Tokens remain on disk. On next launch, getSession() reads them, auto-refreshes if the access token expired. None. Seamless resume.
Device rebooted Same as above. Tokens persist on disk. None.
App deleted / reinstalled Tokens are destroyed. The user:// directory is wiped by iOS when the app is uninstalled. The server-side session still exists in Supabase but the client has no way to reach it. Anonymous account is orphaned forever. On reinstall, signInAnonymously() creates a brand new user. Old creatures, progress, everything is gone.
"Offload App" (iOS storage management) Tokens are preserved. iOS offloading removes the app binary but keeps the Documents and user:// data. When the user reinstalls, the data is restored. None, if tokens are in user://.

Refresh token behavior

Supabase refresh tokens never expire on their own but can only be used once. When you use a refresh token to get a new access token, Supabase issues a new refresh token and invalidates the old one. The client library handles this automatically via an onAuthStateChange listener that fires a TOKEN_REFRESHED event. You must persist the new token pair every time this event fires, or you'll end up with a stale refresh token that's already been consumed.

Sessions can be configured to have a maximum lifetime or inactivity timeout (Pro plan+), but by default, sessions are indefinite. A user who launches the game once a month will still have a valid session as long as the refresh token is intact on the device. If they don't launch for a very long time and you've configured an inactivity timeout, the session terminates server-side and the client gets an error on the next refresh attempt. For a game, don't set an inactivity timeout on anonymous sessions.

CRITICAL: TOKEN PERSISTENCE
Your _store_session() function is the single most important piece of auth code in the game. Every time onAuthStateChange fires with SIGNED_IN or TOKEN_REFRESHED, you must write the new access + refresh token to disk. If you miss a refresh cycle and the old token gets rotated out, the user's session is dead. For anonymous users, that means permanent account loss.

What "skip" means in the post-tutorial prompt

"Skip" means the user stays on their anonymous Supabase session with no linked identity provider. Their creatures and progress are stored server-side under their anonymous user_id, and the session tokens live in user:// on the device. They can play normally. The risk is: if they delete the app, lose their phone, or factory reset, their account is unrecoverable. They have no email, no Game Center ID, no Apple ID attached. There is no recovery path.

This is acceptable as a default state but you should make the risk clear to the user. The "Save your progress?" prompt should communicate: "Your creatures live on this device. If you lose this device or delete the app, they're gone forever. Sign in to protect them." Periodically re-prompt (e.g., when they create their 5th creature, or hit level 10, or after 3 days of play) if they're still anonymous.

Rate limiting and abuse prevention

Default 30 anonymous sign-ups per hour per IP. Enable CAPTCHA in Supabase dashboard. Use RLS policies like (auth.jwt()->>'is_anonymous')::boolean IS FALSE to gate premium features behind linked accounts.

Linking flow

When the user taps "Sign in with Apple" from the post-tutorial prompt, the anonymous user's UUID is preserved. Supabase's linkIdentity() attaches the Apple identity to the existing user record. All game data, progress, and creatures remain on the same user_id. The JWT's is_anonymous claim flips to false, and any RLS-gated features unlock immediately. No data migration, no UUID change, no server-side gymnastics.

GDSCRIPT: SESSION PERSISTENCE PATTERN
const SESSION_PATH = "user://auth_session.json"

func _ready():
    # Listen for ALL auth state changes
    supabase.auth.on_auth_state_change.connect(_on_auth_change)

    # Try to restore existing session from disk
    var saved = _load_session_from_disk()
    if saved:
        await supabase.auth.set_session(saved.access_token, saved.refresh_token)
    else:
        # No saved session: first launch or reinstall
        await supabase.auth.sign_in_anonymously()

func _on_auth_change(event, session):
    if event in ["SIGNED_IN", "TOKEN_REFRESHED"]:
        # ALWAYS persist new tokens to disk immediately
        _save_session_to_disk(session)

func _save_session_to_disk(session):
    var file = FileAccess.open(SESSION_PATH, FileAccess.WRITE)
    file.store_string(JSON.stringify({
        "access_token": session.access_token,
        "refresh_token": session.refresh_token
    }))

func _load_session_from_disk():
    if not FileAccess.file_exists(SESSION_PATH):
        return null
    var file = FileAccess.open(SESSION_PATH, FileAccess.READ)
    return JSON.parse_string(file.get_as_text())
09

Game Center: how it actually works

ENG-CENTRIC
Show implementation details

Game Center authentication is silent, signature-based, and not OAuth. It operates through GKLocalPlayer.local.authenticateHandler, a closure that iOS calls multiple times throughout the app lifecycle—on initial set, on auth state changes, and when the user switches accounts.

What happens on the device

If the user is signed into Game Center via iOS Settings (the default for any device with an Apple ID), the handler fires with isAuthenticated = true and a "Welcome back" banner slides from the top. No UI is presented. No user interaction. This is why Game Center is Tier 1 in the cascade.

If the user is not signed in, a login UIViewController is returned exactly once. If the user dismisses it, the app cannot show it again until the user signs in via Settings manually. This is an iOS-level restriction—there is no workaround.

Identity verification (the crypto handshake)

Game Center provides no JWT, no OAuth token, and no email address. Instead, it uses fetchItems(forIdentityVerificationSignature:) (iOS 13.5+), which returns five values:

ValuePurpose
publicKeyURLURL to Apple's signing certificate at static.gc.apple.com
signatureRSA-SHA256 signature over the verification payload
saltRandom salt included in the signed payload
timestampUnix timestamp (big-endian) when signature was generated
teamPlayerIDPersistent player identifier scoped to your developer team

Your server reconstructs the payload by concatenating teamPlayerID + bundleID + timestamp(bigEndian) + salt, fetches Apple's public certificate from publicKeyURL, and verifies the RSA-SHA256 signature. If it checks out, the user is who they say they are.

SECURITY
Validate that publicKeyURL starts with https://static.gc.apple.com/—an attacker could substitute their own certificate server. Also verify the certificate chain roots to DigiCert and reject signatures older than ~5 minutes to prevent replay attacks.

Player identifiers

teamPlayerID is persistent across all your games under the same Apple Developer team. gamePlayerID is scoped to a single game. Use teamPlayerID as your canonical identifier—it lets you recognize the same player across Bobium Brawlers and any future titles. Also available: displayName, alias, isUnderage, and isMultiplayerGamingRestricted.

Xcode setup

Add the Game Center capability in Signing & Capabilities. This sets the com.apple.developer.game-center entitlement and links GameKit.framework. No Info.plist modifications needed. Game Center must also be enabled in App Store Connect under your app's Services tab. That's it.

10

Bridging Game Center to Supabase

ENG-CENTRIC
Show implementation details

Game Center is not a built-in Supabase provider and can't be added through standard configuration (it's not OAuth/OIDC). The solution is a Supabase Edge Function that verifies Game Center signatures and creates/retrieves Supabase sessions.

Godot / iOS GKLocalPlayer.authenticate() fetchItems() → sig data POST /gamecenter-auth {publicKeyUrl, signature, salt, timestamp, teamPlayerId} HTTPS Edge Function 1. Validate publicKeyUrl domain 2. Fetch Apple cert from URL 3. Verify RSA-SHA256 signature 4. Check timestamp freshness 5. admin.createUser() or lookup 6. admin.generateLink(magiclink) 7. Return session JWT fetch cert static.gc.apple.com Supabase Auth auth.users table email: gc_{id}@gc.internal provider: "gamecenter" gc_team_player_id in metadata JWT Security checklist publicKeyUrl must → static.gc.apple.com Reject sigs older than 5 min Verify cert chain → DigiCert root
Fig 2. Game Center signature verification via Supabase Edge Function.

User creation strategy

The Edge Function creates Supabase users with a synthetic email like gc_{teamPlayerId}@gamecenter.internal since Game Center provides no real email. The teamPlayerID goes into app_metadata for lookup on subsequent logins. Use admin.createUser({ email, email_confirm: true }) to skip verification, then admin.generateLink({ type: 'magiclink' }) to produce a session.

The client receives a standard Supabase JWT and uses it for all subsequent API calls. RLS works normally via auth.uid().

Linking anonymous sessions to Game Center

When Game Center succeeds during Phase 1, the user already has an anonymous Supabase session. Two approaches:

Option A (simpler): The Edge Function receives the anonymous user's JWT alongside the Game Center payload. It verifies the GC signature, then calls admin.updateUserById() on the existing anonymous user to set app_metadata.gc_team_player_id and flip is_anonymous to false. Same UUID, no data migration.

Option B (more standard): The Edge Function creates or finds the GC-linked user, returns a new session, and the client replaces its session. Downside: the anonymous user's data must be migrated to the new user ID. Option A is strongly recommended.

11

Apple and Google sign-in providers

ENG-CENTRIC
Show implementation details

Sign in with Apple

Supabase supports Apple natively via signInWithIdToken(). The iOS flow uses Apple's AuthenticationServices framework: generate a nonce, request authorization via ASAuthorizationAppleIDProvider, pass the resulting identity token to Supabase. Apple provides an email (possibly a private relay address like abc@privaterelay.appleid.com) and the user's name only on first authorization—you must persist the name immediately.

Xcode requirement: Add the "Sign in with Apple" capability, which sets the com.apple.developer.applesignin entitlement.

APP REVIEW
Per Apple's App Review Guidelines, if you offer any third-party sign-in (including Google), you must also offer Sign in with Apple. Since you need Google as a fallback, Apple Sign-In is mandatory regardless.

GodotApplePlugins includes Sign in with Apple support, so the same plugin handles both Game Center and Apple Sign-In.

Google Sign-In

Google's iOS SDK presents a native bottom sheet where the user selects an account. Pass the resulting ID token to signInWithIdToken() with provider: 'google'. Configuration requires creating both a Web Application and iOS OAuth client in Google Cloud Console. The Web client ID and secret go into the Supabase dashboard; the iOS client ID enables native SDK auth.

CONFIG NOTE
Enable "Skip nonce checks" in Supabase's Google provider settings for native iOS sign-in. The Google iOS SDK handles nonce verification internally, and Supabase's server-side check will reject valid tokens if left enabled.

Account linking

Supabase provides linkIdentity() for OAuth providers and updateUser() for email. Enable "Manual Linking" in the Supabase dashboard under Auth > Providers. When an anonymous user links an identity, their UUID is preserved—no data migration. The is_anonymous JWT claim flips to false automatically.

ProviderSupabase methodLink methodGodot plugin
Game CenterCustom Edge Functionadmin.updateUserById()GodotApplePlugins
ApplesignInWithIdToken()linkIdentity()GodotApplePlugins
GooglesignInWithIdToken()linkIdentity()Google Sign-In iOS SDK
EmailsignUp()updateUser({ email })HTTP (no native SDK)
12

Godot plugin landscape

ENG-CENTRIC
Show implementation details

Plugin landscape

PluginArchitectureGC SupportStatus
GodotApplePlugins
migueldeicaza/GodotApplePlugins
SwiftGodot / GDExtension Full (GameKit, StoreKit2, Sign in with Apple) Active, Godot 4.2+, Asset Library
godot-ios-plugins
godot-sdk-integrations/godot-ios-plugins
Legacy Obj-C++ (.gdip) Game Center plugin exists 31 open issues, 21 open PRs
godot-ios-extensions
rktprof/godot-ios-extensions
Swift / GDNative GameKit, StoreKit, Sign in with Apple Maintained, alternative option
supabase-community/godot-engine.supabase Pure GDScript (REST/HTTP) N/A (auth client only) ~228 stars, Auth+DB+Realtime+Storage

GodotApplePlugins is the clear first choice. It's built on SwiftGodot (the modern GDExtension Swift binding), maps 1:1 to Apple's GK*/AS* APIs using snake_case, and is maintained by Miguel de Icaza. Drop the binaries into addons/.

Signal flow for native auth

GDScript calls a plugin method → SwiftGodot bridges to Swift → Swift calls iOS API → iOS presents auth UI (if needed) → Swift receives callback → onComplete.callDeferred() returns data to GDScript.

Platform guards

iOS plugins return null in the Godot editor and on non-iOS platforms. Always guard with ClassDB.class_exists():

GDSCRIPT — LAUNCH AUTH SEQUENCE
var _game_center: Variant = null

func _ready():
    # Always start with anonymous Supabase auth
    var session = await supabase.auth.sign_in_anonymously()
    _store_session(session)

    # Then attempt silent Game Center
    if ClassDB.class_exists("GameCenter"):
        _game_center = ClassDB.instantiate("GameCenter")
        _game_center.authenticate(_on_gc_auth)

func _on_gc_auth(error, player):
    if error == OK:
        # Get signature data for server verification
        var sig_data = await player.fetch_identity_verification_signature()
        # POST to Edge Function with sig + current anon JWT
        var result = await _call_edge_function(
            "gamecenter-auth", {
                "public_key_url": sig_data.public_key_url,
                "signature": sig_data.signature,
                "salt": sig_data.salt,
                "timestamp": sig_data.timestamp,
                "team_player_id": player.team_player_id,
                "anon_user_id": supabase.auth.current_user.id
            })
        if result.ok:
            _store_session(result.session)
    else:
        # Game Center unavailable. User stays anonymous.
        # Will be prompted post-tutorial.
        pass
TESTING
Game Center auth only works on-device or in Simulator with a signed-in Sandbox Apple ID. Test all auth paths on real hardware. The Godot editor will always take the else branch.
13

Xcode entitlements and capabilities

ENG-CENTRIC
Show implementation details
CapabilityEntitlement keyWhen neededPlist changes
Game Center com.apple.developer.game-center Always (Tier 1 auth) None required
Sign in with Apple com.apple.developer.applesignin If offering any 3rd-party sign-in None required
Push Notifications aps-environment If using push for re-engagement None required
Associated Domains com.apple.developer.associated-domains If using universal links for deep linking / magic link email auth None required

All capabilities are added in Xcode under Signing & Capabilities. Godot's iOS export template respects the .entitlements file you configure. GodotApplePlugins documentation covers the exact file paths.

For Google Sign-In: add the reversed Google client ID as a URL scheme in your Info.plist (format: com.googleusercontent.apps.YOUR_CLIENT_ID). No entitlement needed.