SCREECHVR AUTH REVIEW V15: PLAYFAB IDENTITY + PHOTON AUTH
Date: 2026-10-30
Scope: Read-only source and documentation review. No code, Unity files, revisions,
dashboards, or production services changed. V08 remains an unverified draft.
SUMMARY
Current code turns the Meta ID returned to the client into a PlayFab Custom ID,
without proving that ID to PlayFab. Photon normally uses a PlayFab-issued Photon
token, but PhotonVRManager falls back to a connection with no AuthValues after
waiting 20 seconds. These are source-confirmed trust weaknesses. Whether the
Photon fallback is admitted by production Photon settings is unverified.
1. PLAYFAB IDENTITY
Source and flow
- `! Screech VR/Screech VR/Assets/Scripts/Oculus_Login.cs`
- `Start()` initializes Meta Platform and requests `Users.GetLoggedInUser()`.
`OnUserLogin()` assigns `msg.Data.ID.ToString()` to `OculusID` and invokes
`Login()` (source lines approximately 100-181; local source checked).
- `Login()` calls PlayFab `LoginWithCustomID` with `CustomId = OculusID` and
`CreateAccount = true`. The client sends no Meta proof to PlayFab/backend.
- `OnLoginSuccess()` stores `PlayFabId` and `SessionTicket`, then requests a
Photon token. Session ticket is used by authenticated PlayFab client calls;
source inspection found no Meta proof validation or server-side identity
binding in this flow. Protect tickets as credentials; do not log them.
- `AppEntitlementCheck.cs` is a separate client entitlement check and does not
independently authenticate the Meta ID to PlayFab. Its failure behavior is
not a substitute for account identity verification.
Confirmed vulnerability vs uncertainty
- Confirmed: `LoginWithCustomID` accepts the client-provided Meta ID without a
server-verified proof in this path. PlayFab documents CustomId as a title-
generated unique ID and warns that predictable/reused values risk account
impersonation. A modified client can submit another known ID. This is an
authentication design flaw; practical exploitability and any additional live
restrictions are not established here.
- Not verified: PlayFab title API policies, deployed server-side login controls,
account linking/recovery policy, or production enforcement settings.
Meta `getUserProof`
- Official Meta User Verification documentation describes `Users.GetUserProof()`
as a client-provided, one-use nonce; a trusted backend submits nonce plus user
ID to Meta `https://graph.oculus.com/user_nonce_validate` using app credentials.
A successful verification proves the Meta account identity for that request.
- It is not safe to call the client API and trust its result. Backend must call
Meta, ensure the nonce is one-use/fresh, bind the verified identity to the
account, and keep Meta app secret exclusively server-side. Meta says User
Verification does not replace Entitlement Check. User ID Data Use Checkup
permission is required; app eligibility/DUC and SDK compatibility must be
confirmed for this project.
- Recommended flow: Unity obtains Meta user ID + proof nonce; sends both via TLS
to backend; backend verifies with Meta S2S using secret, obtains/uses a stable
verified account key (Meta documents org-scoped ID retrieval after verification),
and maps it to a PlayFab account. Backend then issues/authorizes a short-lived
game credential. Avoid retaining an unverified client ID as account authority.
Migration must preserve existing PlayFab IDs, inventory, purchases, and recovery.
- If direct PlayFab login is retained, a backend-mediated identity exchange must
securely bind verified Meta identity to the intended PlayFab account; do not
put PlayFab title secret or Meta app secret in Unity. Do not assume a custom
ID derived in client code becomes secret or unforgeable.
2. PHOTON AUTHENTICATION
Source and flow
- `! Screech VR/Screech VR/Assets/Scripts/Oculus_Login.cs`: `OnLoginSuccess()`
calls `PlayFabClientAPI.GetPhotonAuthenticationToken` with the configured
Photon Realtime App ID; success stores `PhotonCustomAuthToken` and marks Photon
readiness. The PlayFab session ticket authorizes that request; it is not itself
the Photon token.
- `! Screech VR/Screech VR/Assets/Scripts/PhotonVRManager.cs`: `Start()` starts
`WaitForAuthThenConnect()` when `ConnectOnAwake` is set. The coroutine waits
up to 20 seconds for `Oculus_Login.IsPhotonReady`; on success it calls
`ConnectAuthenticated(PlayFab_Id, PhotonCustomAuthToken)`. That method sets
`AuthenticationValues` to Custom and adds `username` (PlayFab ID) and `token`
(PlayFab Photon token), then connects.
- On timeout/not-ready it calls `Connect()`, which clears
`PhotonNetwork.AuthValues` and connects without those credentials. This is a
confirmed unauthenticated fallback in source. Photon documents anonymous
clients as assigned a random ID when no authentication values are provided.
- Token request failure does not make `IsPhotonReady` true; thus the 20-second
wait reaches the same unauthenticated fallback. No credential-refresh/retry
recovery is implemented in this manager's `OnDisconnected()` path; it updates
state only. `OnConnectedToMaster()` may automatically join a room based on
`JoinRoomOnConnect`.
- `ConnectRandom()` sets auth values but only calls `JoinRandomRoom` in the
inspected method; it is not evidence of a fresh authenticated connect. Audit
its callers and connection lifecycle before changing it.
Confirmed vs dashboard-dependent
- Confirmed: fallback clears auth and attempts connection without PlayFab
custom credentials; timeout and token-fetch failure can reach that code path.
- Dashboard-dependent: Photon application’s custom auth provider URL, anonymous
client option, fail-closed behavior when the provider is unavailable, app-ID
association, and whether the live app accepts the fallback. No dashboard
settings were accessed or verified.
- Reconnect: no explicit application-level credential reacquisition is present
in this manager. Photon may handle its own server-switch/reconnect token flow
after an authenticated connection, but that does not make the initial
unauthenticated fallback safe. Verify the exact PUN version and reconnect
behavior in staging; do not assume reconnect bypasses or enforces auth.
Required Photon dashboard configuration (do not change in this review)
- Configure the Photon Realtime application’s Custom Server authentication
provider URL as PlayFab documents:
`https://<PlayFabTitleId>.playfabapi.com/photon/authenticate`
- Disable “Allow anonymous clients to connect, independently of configured
providers” for the relevant app. Photon’s PlayFab integration marks this
recommended; verify its exact setting in the dashboard.
- Confirm the PlayFab Photon add-on is associated with the same Realtime App ID
used by `GetPhotonAuthenticationToken`; configure/test Voice app authentication
separately if its app ID differs.
- Ensure Photon rejects failed/unavailable custom authentication rather than
accepting fallback; test provider outage behavior and app IDs in a non-prod app.
3. RECOMMENDED IMPLEMENTATION ARCHITECTURE
Unity changes (future work only)
- Gate Photon connect on successful PlayFab login AND successful Photon token
retrieval. On timeout/error, show retry/error state and do not call anonymous
`Connect()`. Keep offline/dev paths explicit and unavailable in production.
- Centralize auth state transitions: authenticated, retryable network failure,
permanent credential/configuration failure, signed-out. Bound retries with
backoff; do not start multiple concurrent login/token requests.
- Reconnect by obtaining a fresh PlayFab Photon token when needed, setting
Custom AuthValues, then connecting. Confirm PUN-managed server switches remain
compatible. Never silently downgrade on reconnect.
- For Meta identity, add `GetUserProof` only with backend S2S validation and an
account migration/linking design. Keep all server credentials backend-only.
Backend changes (future work only)
- Add authenticated Meta-proof verification endpoint: validate Meta nonce and
user ID server-to-server; enforce freshness/one-use, rate limit, strict input
validation, TLS, secret storage, and audit without logging proof/credentials.
- Bind verified stable Meta identity to PlayFab account. Define account recovery,
duplicate-link behavior, migration of existing accounts, and rollback first.
- For Photon custom auth, use PlayFab’s official Photon integration endpoint
unless a concrete requirement demands a custom provider. Do not confuse Worker
`/photonwh/*` webhooks with Photon player authentication: they handle webhook/
CCU events, not player credential validation. No general game-auth endpoint
or Meta proof validator was found in `discord-bot/worker.js`.
- Backend must never trust a PlayFab ID sent alone by client; validate the
PlayFab session ticket server-side when custom backend authorization requires
it. Keep Meta and PlayFab server secrets out of client builds.
4. FAILURE, RECONNECT, AND COMPATIBILITY POLICY
- Meta proof service unavailable: do not create a new unverified account or
silently bind a different identity. Offer retry; existing account access may
follow a documented, verified recovery policy.
- PlayFab login/token request timeout: bounded retry/backoff; no Photon connect.
- Photon auth rejection/provider outage: surface retryable vs configuration
failure; do not fall back to anonymous. Preserve room matchmaking after
authentication succeeds.
- Expired Photon credential/reconnect: obtain fresh token via valid PlayFab
session, then reconnect authenticated. If PlayFab session expired, reauthenticate
through the identity flow. Avoid duplicate Photon managers/connections.
- Roll out with a staging Photon app and test accounts first. Existing users must
retain PlayFab ID, data, currency, owned cosmetics, and IAP entitlements.
5. SMALL REGRESSION TEST PLAN
1. Existing legitimate Meta account logs in; same PlayFab ID and inventory remain.
2. Alter client-supplied Meta ID while proof belongs to another user: backend
rejects mismatch; no account is created/linked to the victim.
3. Reuse an already-consumed Meta proof nonce: rejected; no session issued.
4. Meta unavailable/DUC or permission failure: clear recoverable error; no
unverified identity fallback.
5. PlayFab login succeeds, Photon token succeeds: custom auth connects and room
join/voice/matchmaking behavior is unchanged.
6. Delay/fail Photon-token request beyond 20 seconds: no unauthenticated connect;
retry works after service recovery.
7. Reject token or disable custom-auth provider in staging: Photon refuses
connection; no anonymous session is admitted.
8. Disconnect/reconnect and server switch: fresh/managed auth succeeds; expired
credentials do not trigger an anonymous downgrade or duplicate connection.
9. Test Realtime and Voice app IDs/config independently; verify correct identity
and normal room/voice behavior.
6. REMAINING UNKNOWNS
- Live PlayFab title/API policies, deployed CloudScript/Functions, and any
additional identity binding not present in inspected source.
- Photon dashboard configuration, anonymous-client setting, provider outage
policy, Realtime/Voice app IDs, and production connection path.
- Meta DUC/User ID permission, app eligibility, Unity Platform SDK version/API
availability in Unity 2021.3.32f1, and review requirements.
- Whether Oculus ID vs org-scoped ID is the correct durable account key for this
title; confirm with Meta documentation and migration constraints before design.
- Exact PUN package version and reconnect/server-switch behavior in this project.
- Source review was targeted, not a complete audit of all login callers or every
scene’s PhotonVRManager configuration.
OFFICIAL DOCUMENTATION CONSULTED
- Meta Unity User Verification: https://developers.meta.com/vr/documentation/unity/ps-ownership/
- Meta S2S API basics/secrets: https://developers.meta.com/vr/documentation/unity/ps-s2s-basics/
- PlayFab LoginWithCustomID: https://learn.microsoft.com/en-us/rest/api/playfab/client/authentication/login-with-custom-id
- PlayFab login best practices: https://learn.microsoft.com/en-us/gaming/playfab/identity/player-identity/login/login-basics-best-practices
- PlayFab GetPhotonAuthenticationToken:
https://learn.microsoft.com/en-us/rest/api/playfab/client/authentication/get-photon-authentication-token
- Photon PUN PlayFab integration/dashboard setup:
https://doc.photonengine.com/pun/current/reference/playfab
- Photon PUN auth overview:
https://doc.photonengine.com/pun/current/connection-and-authentication/authentication/overview-auth
No code or production changes. This report is a focused supplement, not a
replacement for V14.
END OF REPORT