Supabase Auth

Supabase handles login. Persistly handles cloud-save sessions.

Auth Bridge is a short token exchange before normal save sync. Persistly verifies the Supabase access token and returns accountId plus accountSessionToken for save/load routes.

Phase 1BSupabase access tokenaccount sessions

Persistly Verification

What Persistly verifies

Persistly checks the Supabase token against the environment configuration selected by the runtime key.

Persistly verifies the Supabase access token signature through the Supabase JWKS endpoint, then checks issuer, audience, expiration, and stable subject.

Persistly uses the verified issuer and subject as the identity key. Email is never the account identity.

Normal save, load, and sync routes do not accept Supabase tokens. They use the Persistly account session returned by Auth Bridge.

Projects using legacy symmetric JWT signing should rotate to Supabase signing keys before using this bridge. Persistly does not ask for JWT secrets.

Supabase Responsibility

What Supabase handles

Supabase remains the player identity system and token issuer for your game.

Supabase handles sign-in UI, credentials, password reset, social provider setup, sessions, and token issuance.

Your game decides when to ask the player to sign in and when to refresh the Supabase access token.

Persistly does not store Supabase access tokens, replace Supabase user management, or revoke Supabase sessions.

Dashboard Setup

Enable Supabase Auth per environment.

Stage and Production have separate settings so test users and production players can stay isolated.

01

Create or choose the Supabase project your game already uses for player sign-in.

02

In the Persistly dashboard, open the project Authentication page and add Supabase Auth to Stage first.

03

Enter the Supabase project URL such as https://your-project-ref.supabase.co. Do not enter anon keys, service-role keys, JWT secrets, or database URLs.

04

Leave audience empty unless your Supabase project uses a non-default JWT audience. The default audience is authenticated.

05

Paste a Supabase access token into the dashboard test panel to verify Stage before using it in a game.

06

Use Free workspace Stage keys for testing. Upgrade before using Production Auth Bridge with live players.

07

Repeat the same review for Production only after the production build and Supabase settings are ready.

08

Use Supabase Auth in the game to obtain the signed-in player's access token.

09

Pass that access token to the Persistly SDK auth helper, then continue using normal save and load helpers.

Configure Stage first with a stage runtime key, then repeat the review for Production when the production build is ready.

Free workspaces can test Supabase Auth Bridge on Stage. Production Auth Bridge requires a paid workspace plan.

Use the Supabase project URL from the Supabase project that signs in your players.

Use the test-token panel to verify the configured project before putting the runtime key into a game build.

JavaScript SDK Sign-In

Exchange a Supabase access token before saving.

TYPESCRIPT
import { PersistlyGameSaves } from "@persistlyapp/sdk";
import { createClient } from "@supabase/supabase-js";

const supabase = createClient("https://your-project-ref.supabase.co", "SUPABASE_ANON_KEY");

await PersistlyGameSaves.configure({
  runtimeKey: "ps_test_replace_me",
  accountMode: "authRequired",
});

const { data } = await supabase.auth.getSession();
const accessToken = data.session?.access_token;

if (!accessToken) {
  showSignInUI();
  return;
}

await PersistlyGameSaves.shared.signInWithSupabaseToken(accessToken);

await PersistlyGameSaves.shared.saveData({
  level: 5,
  coins: 1200,
});

Unity SDK Sign-In

Use the Supabase token helper in Unity.

C#
using Persistly.Unity;

await PersistlyGameSaves.ConfigureAsync(new PersistlyGameSavesSettings("ps_test_replace_me")
{
    AccountMode = PersistlyAccountMode.AuthRequired,
});

var accessToken = await GetSupabaseAccessTokenAsync();
await PersistlyGameSaves.Shared.SignInWithSupabaseTokenAsync(accessToken);

await PersistlyGameSaves.Shared.SaveDataAsync(new PlayerData
{
    Level = 5,
    Coins = 1200,
});

Godot SDK Sign-In

Use the Supabase token helper in Godot.

GDSCRIPT
const PersistlyGameSaves = preload("res://addons/persistly/persistly_game_saves.gd")

var persistly := PersistlyGameSaves.new()
persistly.configure({
  "runtime_key": "ps_test_replace_me",
  "account_mode": "authRequired",
})

var access_token := await get_supabase_access_token()
await persistly.sign_in_with_supabase_token(access_token)

persistly.save_data({
  "level": 5,
  "coins": 1200,
})

Saving

Saving after sign-in works the same way.

Auth Bridge changes how the account session is issued. It does not change the normal save model.

After sign-in, the SDK stores the Persistly account session locally and normal save helpers keep using that session.

saveData and saveSlot still write local data first. Cloud sync remains explicit through forceSyncData, forceSync, or due-sync helpers.

Normal save, load, and sync calls use the Persistly account session, not a Supabase token.

Sign Out

Sign-out behavior is local cleanup plus Supabase sign-out.

Keep logout explicit so one local player cannot inherit another player's cached save session.

Sign out of Supabase through the Supabase SDK so your game UI returns to a signed-out state.

Clear the local Persistly account/session/slot cache on that device so the next local player cannot read cached saves.

Sign-out is local cleanup. It does not delete the remote Persistly account or revoke Supabase sessions.

Common Errors

Handle auth errors as player-safe recovery states.

auth_bridge_requires_paid_plan: the request used a Production runtime key from a Free workspace. Test with a Stage key or upgrade before production launch.

provider_not_configured: Supabase Auth is not configured for the Persistly environment selected by the runtime key.

provider_not_enabled: Supabase Auth is configured but disabled for this environment.

supabase_project_url_required: the Persistly environment is missing its Supabase project URL.

supabase_project_url_invalid: the configured Supabase project URL is not a valid HTTPS URL.

supabase_token_missing: the auth session request did not include a Supabase access token.

supabase_token_expired: the Supabase access token expired. Refresh it with Supabase and retry.

supabase_project_mismatch: the token issuer does not match the configured Supabase project URL.

supabase_audience_mismatch: the token audience does not match the configured audience.

supabase_token_invalid: the token is malformed, cannot be verified, or is missing required claims.

account_auth_conflict: this Supabase identity is already linked to a different Persistly account. Show recovery UI instead of merging silently.

Security Notes

Keep tokens and Supabase secrets out of logs.

Never log Supabase access tokens, Persistly account session tokens, or full auth responses.

Use Stage runtime keys for development and Production runtime keys only in production builds.

Do not paste Supabase anon keys, service-role keys, JWT secrets, database URLs, or API keys into Persistly Auth Bridge configuration.

Do not store the Supabase token as the save identity. Store the Persistly accountId and accountSessionToken through the SDK's normal local storage path.

Treat sign-out as a local Persistly cache purge plus a Supabase sign-out in your game.

Related

Continue with account mode and direct API details.

Account modes

Use authRequired for Supabase Auth Bridge and keep anonymousFirst for no-auth games.

Direct API example

Advanced provider-token exchange request for custom engines and SDK authors.