Skip to main content

Authentication

The MCE Online layer supports multiple authentication methods through Nakama. All authentication flows are managed by AuthService (in Auth/AuthService.cs) and SessionManager, both initialized automatically by NakamaManager at startup.

Connection States

The ConnectionState enum tracks the full lifecycle of the online connection:

StateDescription
DisconnectedNot connected and not attempting to connect
ConnectingCurrently attempting to establish connection
ConnectedSuccessfully connected and authenticated
ReconnectingConnection lost, attempting automatic reconnect
OfflineRunning in offline mode (server unavailable or disabled)
FailedConnection failed after all retry attempts

You can subscribe to state changes via NakamaManager.Instance.OnStateChanged.

NakamaManager.Instance.OnStateChanged += (state) =>
{
Debug.Log($"Connection state: {state}");
};

Convenience properties are available on NakamaManager:

  • IsConnected -- returns true only when state is Connected.
  • IsOffline -- returns true when state is Offline or Disconnected.

Authentication Methods

MCE supports the following AuthMethod values: Email, DeviceId, Discord, Google, Apple, Facebook, and Custom.

Device Authentication (Auto-Login)

The simplest method. Uses SystemInfo.deviceUniqueIdentifier to create an anonymous account automatically. Ideal for mobile and first-time play.

bool success = await NakamaManager.Instance.ConnectWithDeviceAsync();

Under the hood, AuthService.AuthenticateDeviceAsync() calls Client.AuthenticateDeviceAsync(deviceId, create: true), which creates a new Nakama account on first use and logs into it on subsequent calls. The device ID is truncated in logs for privacy.

Email / Password Authentication

Supports both registration (create: true) and login (create: false).

// Register a new account
bool registered = await NakamaManager.Instance.ConnectWithEmailAsync(
"player@example.com", "securepassword", createAccount: true);

// Login to existing account
bool loggedIn = await NakamaManager.Instance.ConnectWithEmailAsync(
"player@example.com", "securepassword", createAccount: false);

You can also use the lower-level AuthService directly:

OnlineSession session = await NakamaManager.Instance.Auth.AuthenticateEmailAsync(
email, password, create: true);

The returned OnlineSession wraps Nakama's ISession and exposes: UserId, DisplayName, Token, RefreshToken, and ExpiresAt.

SSO Authentication (Discord, Google, Apple)

SSO providers are enabled per-provider in OnlineConfig:

  • EnableDiscordSSO (default: true)
  • EnableGoogleSSO (default: true)
  • EnableAppleSSO (default: true)

OAuth client IDs are also configured in OnlineConfig (DiscordClientId, GoogleClientId).

// Google
bool success = await NakamaManager.Instance.ConnectWithSSOAsync(
AuthMethod.Google, googleIdToken);

// Apple
bool success = await NakamaManager.Instance.ConnectWithSSOAsync(
AuthMethod.Apple, appleIdentityToken);

// Discord (uses custom auth flow with Discord user ID)
bool success = await NakamaManager.Instance.ConnectWithSSOAsync(
AuthMethod.Discord, discordUserId);

Google and Apple use Nakama's built-in AuthenticateGoogleAsync / AuthenticateAppleAsync. Discord and Facebook route through AuthenticateCustomAsync since Nakama does not have a native Discord auth provider.

Account Linking

Players can link multiple authentication methods to a single account. This lets them start with device auth and later add email or SSO for cross-device access.

bool linked = await NakamaManager.Instance.Auth.LinkAccountAsync(
AuthMethod.Google, googleToken);

bool linked = await NakamaManager.Instance.Auth.LinkAccountAsync(
AuthMethod.Discord, discordToken);

LinkAccountAsync uses Client.LinkGoogleAsync, Client.LinkAppleAsync, or Client.LinkCustomAsync depending on the method.

Session Persistence

SessionManager handles saving and restoring authentication tokens using PlayerPrefs:

  • Token key: mce_nakama_token
  • Refresh token key: mce_nakama_refresh

On successful authentication, SaveNakamaSession(session) persists both tokens. On app restart, LoadNakamaSession(client) restores the session via Nakama.Session.Restore(token, refresh). If the restored session is expired, it is cleared automatically.

// Check if a valid session exists
bool hasSession = NakamaManager.Instance.SessionMgr.HasValidSession();

// Manually clear session (logout)
NakamaManager.Instance.SessionMgr.ClearSession();

Post-Authentication Flow

After any successful authentication, NakamaManager.FinalizeConnection() performs the following sequence:

  1. Stores Session, UserId, DisplayName, and SessionToken.
  2. Saves the session via SessionManager.
  3. Creates a WebSocket via Client.NewSocket(useMainThread: true).
  4. Hooks socket events: Closed, ReceivedError, ReceivedMatchState, ReceivedChannelMessage, ReceivedNotification, ReceivedMatchmakerMatched, ReceivedStatusPresence.
  5. Connects the socket with Socket.ConnectAsync(session).
  6. Initializes online services asynchronously:
    • WorldSync.InitializeAsync() -- joins the world match.
    • Chat.JoinGlobalChannelAsync() -- joins the global chat room.
    • Friends.RefreshFriendsListAsync() -- loads friends and follows their status.
    • Housing.InitializeAsync() -- if EnableHousing is on.
    • Mods.LoadInstalledModsAsync() -- if EnableModSupport is on.
  7. Fires OnConnected and registers the OnlineCommandBridge.

Auto-Reconnect

When the socket closes unexpectedly and OnlineConfig.AutoReconnect is true, NakamaManager automatically attempts to reconnect using exponential backoff:

  • Delay formula: min(2 * 2^(attempt-1), 30) seconds.
  • Maximum attempts: OnlineConfig.MaxReconnectAttempts (default: 5).
  • Reconnect restores from the saved session. If the session is expired, it falls back to offline mode.

The state transitions to Reconnecting during attempts.

Offline Fallback

When OnlineConfig.AllowOfflineFallback is true (the default), any connection failure gracefully falls back to ConnectionState.Offline. The entire game continues to work locally -- the online layer is fully optional.

Display Name

After authentication, you can update the player's display name:

bool updated = await NakamaManager.Instance.Auth.UpdateDisplayNameAsync("NewName");

Error Handling

Authentication errors are surfaced through the NakamaManager.OnConnectionError event:

NakamaManager.Instance.OnConnectionError += (errorMessage) =>
{
Debug.LogError($"Connection error: {errorMessage}");
// Show error dialog to the player
};

All auth methods catch exceptions internally and log them with the [MCE Online] or [Auth] prefix.

Configuration Reference

Key settings in OnlineConfig (ScriptableObject at Resources/OnlineConfig):

FieldDefaultDescription
ServerHost127.0.0.1Nakama server hostname
ServerPort7350Nakama server port
ServerKeydefaultkeyNakama server key
UseSSLfalseUse HTTPS/WSS
ConnectionTimeout10Timeout in seconds
AutoReconnecttrueAuto-reconnect on disconnect
MaxReconnectAttempts5Max retry count
AllowOfflineFallbacktrueFall back to offline mode on failure
EnableDiscordSSOtrueEnable Discord auth
EnableGoogleSSOtrueEnable Google auth
EnableAppleSSOtrueEnable Apple auth

Security Best Practices

  • Never expose ServerKey in builds intended for distribution. Use Nakama's environment-specific keys.
  • Prefer SSO or email auth for production. Device auth is convenient for development and mobile quick-start but cannot be recovered if the device is wiped.
  • Enable EnableServerAuthority in OnlineConfig for production. This routes all state-changing operations (items, money, teleport) through server validation via the OnlineCommandBridge.
  • Session tokens are stored in PlayerPrefs. On platforms where PlayerPrefs is not secure (e.g., PC), consider encrypting the token at rest.