Table of Contents

Class BaseAuthenticatorCore<TConnection>

Namespace
FishMMO.Auth.Implementation
Assembly
FishMMO-ServerAuth.dll

Abstract engine-independent base for all server authenticators. Provides X25519 ECDH handshake logic, stale-auth TTL sweeps, per-IP and global handshake rate limiting, and connection auth-state tracking — with no dependency on Unity, FishNet, or any game-engine type.

Concrete implementations supply transport-specific callbacks (broadcast, disconnect, IP resolution) by implementing the abstract members, then call OnHandshakeReceived(TConnection, byte[], byte[], string, ushort, ushort, string) from their transport layer.

public abstract class BaseAuthenticatorCore<TConnection>

Type Parameters

TConnection

The type representing a network connection.

Inheritance
BaseAuthenticatorCore<TConnection>
Derived
Inherited Members

Constructors

BaseAuthenticatorCore(IAccountManager<TConnection>)

Initializes the core with the required account manager.

protected BaseAuthenticatorCore(IAccountManager<TConnection> accountManager)

Parameters

accountManager IAccountManager<TConnection>

The account manager instance.

Fields

AuthHardDeadlineSeconds

Hard deadline in seconds for any single authentication attempt. RefreshAuthTtl(TConnection) will not extend a connection's TTL beyond this absolute limit from its original start time, preventing unbounded TTL extension.

protected const float AuthHardDeadlineSeconds = 60

Field Value

float

AuthStaleTtlSeconds

Authentication TTL in seconds. Connections that do not complete auth within this window are purged.

protected const float AuthStaleTtlSeconds = 15

Field Value

float

AuthSweepMaxRemovals

Maximum stale auth entries purged per sweep.

protected const int AuthSweepMaxRemovals = 64

Field Value

int

AuthSweepMaxScan

Maximum stale auth entries scanned per sweep.

protected const int AuthSweepMaxScan = 256

Field Value

int

HandshakeIpBurstLimit

Maximum Phase-2 handshake completions accepted from one IP inside HandshakeIpWindowSeconds. The old fixed 0.25 s debounce keyed the whole handshake round trip on one interval: any second completion inside the window — a player behind the same NAT as another, or a re-login whose connect+token+challenge cycle finishes faster than the window on a sub-10 ms link — was silently disconnected. A burst of 8 covers the legitimate worst case (a household logging in together, a fast reconnect loop) without meaningfully weakening the sustained per-IP throttle the limiter exists for.

protected const int HandshakeIpBurstLimit = 8

Field Value

int

HandshakeIpWindowSeconds

Duration of the per-IP Phase-2 handshake measurement window. Combined with HandshakeIpBurstLimit this sustains 4 completed handshakes/second/IP (unchanged from the previous single-deadline debounce) while allowing a burst of near-simultaneous completions from one IP.

protected const float HandshakeIpWindowSeconds = 2

Field Value

float

HandshakeRateLimitSweepMaxRemovals

Maximum entries removed per handshake rate-limit sweep.

protected const int HandshakeRateLimitSweepMaxRemovals = 2048

Field Value

int

HandshakeRateLimitSweepMaxScan

Maximum entries scanned per handshake rate-limit sweep.

protected const int HandshakeRateLimitSweepMaxScan = 4096

Field Value

int

MaxGlobalHandshakesPerSecond

Maximum X25519 handshakes accepted in a single 1-second window.

protected const int MaxGlobalHandshakesPerSecond = 500

Field Value

int

MaxPendingAuthConnections

Maximum number of concurrent pending authentication connections.

protected const int MaxPendingAuthConnections = 10000

Field Value

int

Properties

AccountManager

The account manager for this authenticator.

protected IAccountManager<TConnection> AccountManager { get; }

Property Value

IAccountManager<TConnection>

ExpectedGameVersion

Expected game version string (e.g. "0.1.0"). Set by the server host before connections are accepted. If null or empty, game version validation is skipped (development safety). When set, clients with a mismatched ClientHandshake.GameVersion are rejected with VersionMismatch.

public string ExpectedGameVersion { get; set; }

Property Value

string

IsWorkerIdle

Returns true when no async worker operations are in-flight. Subclasses with bounded-channel workers should override to check channel emptiness. Default returns true.

public virtual bool IsWorkerIdle { get; }

Property Value

bool

LogPrefix

Log source tag used in all log messages emitted by this core.

protected virtual string LogPrefix { get; }

Property Value

string

Methods

BroadcastAuthResult(TConnection, ClientAuthenticationResult, bool)

Broadcasts an authentication result to a single connection.

protected abstract void BroadcastAuthResult(TConnection conn, ClientAuthenticationResult result, bool reliable)

Parameters

conn TConnection

Target connection.

result ClientAuthenticationResult

Auth result code.

reliable bool

True for reliable delivery, false for unreliable.

BroadcastCookieChallenge(TConnection, byte[])

Sends a cookie-challenge ServerHandshake response to the client. Called on the network-receive thread — must be non-blocking.

protected abstract void BroadcastCookieChallenge(TConnection conn, byte[] cookie)

Parameters

conn TConnection

The target connection.

cookie byte[]

The HMAC cookie to send.

BroadcastServerHandshake(TConnection, byte[], ushort)

Sends the final ServerHandshake response (with the server's X25519 public key) to complete ECDH key agreement. Called on the network-receive thread — must be non-blocking.

protected abstract void BroadcastServerHandshake(TConnection conn, byte[] serverPublicKey, ushort agreedVersion)

Parameters

conn TConnection

The target connection.

serverPublicKey byte[]

Server's ephemeral X25519 public key.

agreedVersion ushort

Negotiated protocol version.

ClearTransientAuthState(int)

Clears transient per-connection authenticator TTL tracking state.

protected void ClearTransientAuthState(int clientId)

Parameters

clientId int

Connection client ID.

DisconnectConnection(TConnection, bool)

Disconnects the specified connection.

protected abstract void DisconnectConnection(TConnection conn, bool graceful)

Parameters

conn TConnection

The connection to disconnect.

graceful bool

If true, attempt a graceful close; otherwise force-close immediately.

EnqueueMainThread(TConnection, Action)

Enqueues an action to be executed on the main/UI thread. Implementations using Unity must marshal all network API calls (Broadcast, Disconnect) via this method. Non-Unity implementations may execute immediately or use their own dispatcher.

protected abstract void EnqueueMainThread(TConnection conn, Action action)

Parameters

conn TConnection

The connection context (for lifetime checking).

action Action

The action to enqueue.

GetConnectionAddress(TConnection)

Returns the remote IP address (or equivalent string identifier) for the connection. Used for cookie challenge IP binding and rate limiting.

protected abstract string GetConnectionAddress(TConnection conn)

Parameters

conn TConnection

Returns

string

GetConnectionClientId(TConnection)

Returns the numeric client ID for the connection (e.g., FishNet ClientId). Used as the key for TTL tracking dictionaries.

protected abstract int GetConnectionClientId(TConnection conn)

Parameters

conn TConnection

Returns

int

HandleConnectionStopped(TConnection)

Called by the hosting transport layer when a connection has been disconnected. Purges all authenticator state for the connection without disconnecting (already stopped).

public void HandleConnectionStopped(TConnection conn)

Parameters

conn TConnection

The stopped connection.

InitializeWorkers(CancellationToken)

Generates a fresh cookie HMAC key and starts protocol-specific workers. Must be called before accepting connections.

public void InitializeWorkers(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

Token for signalling graceful shutdown.

InitializeWorkersCore(CancellationToken)

Subclass-specific worker initialization: create channels and start worker tasks. Called after the base generates the cookie key.

protected abstract void InitializeWorkersCore(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

Token for signalling worker shutdown.

IsConnectionAuthenticated(TConnection)

Returns whether this connection has already completed authentication. Called on the network-receive thread — must be thread-safe and non-blocking.

protected abstract bool IsConnectionAuthenticated(TConnection conn)

Parameters

conn TConnection

Returns

bool

OnAuthSweep()

Override for subclass-specific logic that runs alongside the stale-auth sweep.

protected virtual void OnAuthSweep()

OnHandshakeDeferred(TConnection)

Invoked when a handshake cannot be admitted because the pending authentication cap (MaxPendingAuthConnections) has been reached. Override to implement a login queue — return true if the connection was queued and should NOT be disconnected; return false (default) to drop the handshake.

protected virtual bool OnHandshakeDeferred(TConnection conn)

Parameters

conn TConnection

The connection that is being deferred.

Returns

bool

true if the connection was queued; false to reject.

OnHandshakeReceived(TConnection, byte[], byte[], string, ushort, ushort, string)

Processes an incoming client handshake. Must be called from the transport layer (e.g., on receipt of a ClientHandshakeBroadcast). Implements a two-phase stateless cookie challenge followed by X25519 ECDH key agreement. Runs with no blocking I/O — safe to call on a network-receive thread.

public void OnHandshakeReceived(TConnection conn, byte[] publicKey, byte[] cookie, string connectionToken, ushort minVersion, ushort maxVersion, string gameVersion = "")

Parameters

conn TConnection

The network connection.

publicKey byte[]

Client's X25519 ephemeral public key (32 bytes). Must not be null.

cookie byte[]

Cookie echoed from a prior challenge, or null on first attempt.

connectionToken string
minVersion ushort

Minimum protocol version supported by the client.

maxVersion ushort

Maximum protocol version supported by the client.

gameVersion string

OnPurgeConnectionState(TConnection)

Override for subclass-specific cleanup during connection purge. Called before AccountManager.RemoveConnectionAccount but after ClearTransientAuthState(int) has removed TTL tracking.

protected virtual void OnPurgeConnectionState(TConnection conn)

Parameters

conn TConnection

The connection being purged.

OnTick()

Override for subclass-specific per-tick logic (e.g., additional periodic sweeps).

protected virtual void OnTick()

PurgeConnectionAuthState(TConnection, bool)

Purges all authenticator state for a connection and optionally disconnects it. TTL tracking is cleared before disconnect to prevent races.

protected void PurgeConnectionAuthState(TConnection conn, bool disconnect)

Parameters

conn TConnection

Connection to purge.

disconnect bool

If true, disconnect the client after purge.

RefreshAuthTtl(TConnection)

Resets the TTL timestamp for a tracked connection to UtcNow. Call from async workers at meaningful progress points to prevent premature sweeping. Refuses to refresh beyond AuthHardDeadlineSeconds from original start.

protected void RefreshAuthTtl(TConnection conn)

Parameters

conn TConnection

Connection whose TTL to refresh.

ResolveRateLimitKey(TConnection)

Resolves a rate-limit key for a connection. Override to return a connection-ID string in proxy/NAT deployments where all clients share the same transport-level IP. Default: returns the normalized remote IP address.

protected virtual string ResolveRateLimitKey(TConnection conn)

Parameters

conn TConnection

The network connection.

Returns

string

A string key suitable for per-identity rate limiting.

ShutdownWorkers()

Gracefully shuts down all async workers and zeroes sensitive key material. Calls ShutdownWorkersCore() first to allow subclasses to complete channel writers for graceful worker exit.

public void ShutdownWorkers()

ShutdownWorkersCore()

Subclass-specific worker shutdown: complete channel writers, null channel references, and clear subclass-specific state. Called BEFORE the base zeroes the cookie key.

protected abstract void ShutdownWorkersCore()

Tick()

Runs the stale-auth TTL sweep and the handshake rate-limit sweep. Must be called periodically by the hosting environment (e.g., every server tick or Update frame).

public void Tick()

TrackAuthStart(TConnection)

Starts auth TTL tracking for a connection if not already tracked. Returns false if the pending authentication cap has been reached.

protected bool TrackAuthStart(TConnection conn)

Parameters

conn TConnection

Connection entering the authentication flow.

Returns

bool

true if tracking was started; false if the cap was reached.