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.
gw server create <app> --name eu-1 --endpoint 203.0.113.5:27777The 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:
| Variable | Values | Default |
|---|---|---|
GAMEWAY_TICKETS | off, optional, required | off |
GAMEWAY_TICKETS_ONLINE | off, best_effort, required | off |
GAMEWAY_APP_ID | your app id | required unless off |
GAMEWAY_SERVER_ID | the id from server create | unset: only tickets for any server are accepted |
GAMEWAY_PUBLIC_ENDPOINTS | comma-separated ip:port players connect to | unset: the game may fill its own |
GAMEWAY_SERVER_KEY | the gws_ key, only for online confirmation | unset |
GAMEWAY_API | the API address, to refresh public keys and confirm online | unset |
GAMEWAY_KEYRING_FILE | a file to cache the signed public keys | unset |
| Situation | `off` | `optional` | `required` |
|---|---|---|---|
| No ticket | let in as before | let in, as anonymous | reject |
| Invalid ticket | ignored | let in as anonymous, never as the claimed player | reject with the reason |
| Valid ticket | ignored | let in as that player | let 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.
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
}
}- On start,
InitFromEnvironmentreads the variables. A bad value, a missing app id, orrequiredmode without endpoints, an API address or fresh keys is an error result: fix it before you accept players. - For each connection,
Throttle(peerIp)first, thenVerifyorVerifyBase64Url. A good result carries the player id and the display name if the player allowed it. - With online confirmation on, call
BeginRedeem(ticket), keep the connection pending, and pollPollEventuntil the answer arrives. A pass already used, or from a banned player, is refused. - Remember
clientIdtouserIdyourself, 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
| Code | Meaning |
|---|---|
TicketMissing | The connection carried no ticket. |
TicketMalformed, TicketBadSignature, TicketUnknownKid | The text is damaged, not signed by the platform, or signed by a key this server does not know. Refresh keys. |
TicketExpired, TicketNotYetValid | The pass is older than its lifetime, or the server clock is wrong. |
TicketWrongApp, TicketWrongAudience | The pass is for another app or another server address. |
TicketReplayed | The same pass arrived again. |
TicketRedeemUnavailable | Online confirmation was asked for and the platform could not be reached. |
TicketBanned | The 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_KEYSat 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