Skip to content

Docs · 04

Online passes on dedicated servers

Let a dedicated server learn, offline and in a few microseconds, which Gameway account is connecting, without a password or a lookup.

4 min readUpdated 4 Oct 2026

Documentation sections

Online passes work end to end today: the app issues them, the SDK hands them to your server and your server checks them with the keys below. The names are the ones in the SDK package today; read the changelog of the version you are given.

What a pass is

When a player starts your game from Gameway, the game can ask the platform for a launch ticket ("a pass") for one server address. The ticket is a small signed token that names the player, the app and the server. The player's game sends it in the connection request; your server checks the signature with a public key it already has. No call to Gameway is needed, and a ticket for another game, another server or another player's address does not verify.

You can also ask for each pass to be confirmed online, once: then a pass cannot be replayed even inside its short lifetime.

Register your server

Every dedicated server has an id that the ticket is bound to, and a list of the addresses players connect to.

Terminal
gw server create <app> --name eu-1 --endpoint 203.0.113.5:27777

The command prints the server id and a secret key that starts with gws_. The key is shown once: put it in the server's environment and nowhere else. gw server rotate-key <app> <serverId> --yes makes a new one and retires the old.

A ticket is valid only for an address you registered. Behind NAT or a load balancer, register the address players really connect to.

Switch it on, gently

Servers keep working exactly as before until you opt in. Set the mode with environment variables:

VariableValuesDefault
GAMEWAY_TICKETSoff, optional, requiredoff
GAMEWAY_TICKETS_ONLINEoff, best_effort, requiredoff
GAMEWAY_APP_IDyour app idrequired unless off
GAMEWAY_SERVER_IDthe id from server createunset: only tickets for any server are accepted
GAMEWAY_PUBLIC_ENDPOINTScomma-separated ip:port players connect tounset: the game may fill its own
GAMEWAY_SERVER_KEYthe gws_ key, only for online confirmationunset
GAMEWAY_APIthe API address, to refresh public keys and confirm onlineunset
GAMEWAY_KEYRING_FILEa file to cache the signed public keysunset
Situation`off``optional``required`
No ticketlet in as beforelet in, as anonymousreject
Invalid ticketignoredlet in as anonymous, never as the claimed playerreject with the reason
Valid ticketignoredlet in as that playerlet in as that player

Start with optional: nobody is locked out while players update, and your logs show how many arrive with a valid pass. Move to required when nearly all do.

Online confirmation needs the server to reach Gameway over HTTPS. In a container, install the CA certificates.

Check a pass in your server

The Unity package has GamewayServer for this. The same checks exist as a C library (gw_srv_*) for servers that are not made with Unity.

C#
using Gameway.Sdk;
using Gameway.Sdk.Server;

static class PassCheck
{
    static GamewayServer server;

    public static void Start()
    {
        // reads the GAMEWAY_* variables below; "off" (the default) changes nothing
        var r = GamewayServer.InitFromEnvironment("203.0.113.5:27777", out server);
        if (r.IsError()) UnityEngine.Debug.LogError("Gameway server: " + r.CodeName());
    }

    // in your connection approval, with the ticket text the client put in its connect payload
    public static GwResult Check(string peerIp, string ticketText, out GwTicketInfo info)
    {
        info = default;
        var t = server.Throttle(peerIp);          // keep floods away from the signature check
        if (t.IsError()) return t;
        return server.VerifyBase64Url(ticketText, out info);   // checked offline, thread-safe
    }
}
  1. On start, InitFromEnvironment reads the variables. A bad value, a missing app id, or required mode without endpoints, an API address or fresh keys is an error result: fix it before you accept players.
  2. For each connection, Throttle(peerIp) first, then Verify or VerifyBase64Url. A good result carries the player id and the display name if the player allowed it.
  3. With online confirmation on, call BeginRedeem(ticket), keep the connection pending, and poll PollEvent until the answer arrives. A pass already used, or from a banned player, is refused.
  4. Remember clientId to userId yourself, and decide what a second login of the same player does. Do not trust a player id from anywhere but the checked ticket.

Why a pass fails

CodeMeaning
TicketMissingThe connection carried no ticket.
TicketMalformed, TicketBadSignature, TicketUnknownKidThe text is damaged, not signed by the platform, or signed by a key this server does not know. Refresh keys.
TicketExpired, TicketNotYetValidThe pass is older than its lifetime, or the server clock is wrong.
TicketWrongApp, TicketWrongAudienceThe pass is for another app or another server address.
TicketReplayedThe same pass arrived again.
TicketRedeemUnavailableOnline confirmation was asked for and the platform could not be reached.
TicketBannedThe player may not play this app right now.

Show your own friendly text for these. Do not print raw codes to players.

Keys and rotation

The public keys a server uses are signed by a root key that is built into the SDK. The platform rotates the signing keys on a schedule and lists the current ones at GET /v1/keys/tickets. A server with GAMEWAY_API set refreshes them on its own; one without it uses the keys in its keyring file and in the SDK build.

  • Do not copy keys by hand.
  • Keep GAMEWAY_ALLOW_DEV_KEYS at 0. Only local test servers use development keys.
  • If a server key leaks, rotate it at once. Passes are not secrets, but the server key lets someone confirm passes in your name.

Gameway · 2026-10-04