Skip to content

Custom Token Sign In

automoto edited this page Oct 26, 2026 · 2 revisions

Custom Token Sign-In

With custom tokens, your own backend controls player identity. Your backend signs a short-lived JWT for a player. The game client sends the JWT to POST /v1/auth/custom-token. GG Scale checks the signature and returns a session. Use this method when you already have accounts, for example on a website or a game backend.

Your backend signs with a private key. The private key stays on your servers. GG Scale stores only the public key. Thus, a leak of the GG Scale database does not let an attacker make player sessions.

1. Make a key pair

Use Ed25519 if your JWT library supports it:

openssl genpkey -algorithm ed25519 -out custom-token-private.pem
openssl pkey -in custom-token-private.pem -pubout -out custom-token-public.pem

You can also use an RSA key of 2048 bits or more, and sign with RS256. The key type sets the algorithm: EdDSA for an Ed25519 key, RS256 for an RSA key. GG Scale rejects all other algorithms.

2. Configure GG Scale

In the control panel, open Account Tenant settings and go to Custom token sign-in. Paste the contents of custom-token-public.pem and save. To turn off custom-token sign-in, save an empty value.

The key applies to all Game Projects in the Account Tenant. Each player belongs to the Game Project of the API key that the client sends.

3. Sign tokens on your backend

The token must have these claims:

  • external_id is your stable user id. It must not be empty.
  • aud must be ggscale-custom-token.
  • exp is required. Keep it short, a few minutes.
  • iat is optional. If you set it, it must not be more than 5 minutes in the future.

GG Scale allows 30 seconds of clock difference when it checks exp.

token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, jwt.MapClaims{
    "external_id": "user-42",
    "aud":         "ggscale-custom-token",
    "exp":         time.Now().Add(5 * time.Minute).Unix(),
})
signed, err := token.SignedString(ed25519PrivateKey)

Do not start external_id with anon_, user_, or steam:. GG Scale uses these prefixes for anonymous, email, and Steam players. A token with such an id signs in as the GG Scale player that has that id in the Game Project. Add your own prefix, for example acme:42.

Your backend gives the token to the game client, and the client sends it immediately. GG Scale accepts a token more than one time until it expires, so keep exp short.

4. Send the token from the client

curl -s -X POST http://localhost:8080/v1/auth/custom-token \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{"token":"eyJhbGciOiJFZERTQSIs..."}'

The response has the same session fields as the other auth calls (access_token, refresh_token, player_id, expires_at). The first call for an external_id creates the player. Later calls return the same player.

Common errors

Status Meaning Fix
400 The Account Tenant has no public key. Save the key in the control panel.
401 The signature, algorithm, aud, exp, iat, or external_id check failed. All of these failures give the same error. Check the key, the algorithm, the audience, and the server clock.
403 account banned The Account Tenant banned this player. This is not a token problem.
403 player creation is disabled The Account Tenant is at its player limit. This occurs only for a new external_id. Raise the limit. See Quotas, Tiers, and Entitlements.

Change the key

Save the new public key in the control panel. At the same time, change the private key on your backend. Tokens signed with the old key stop working immediately. Tokens are valid for only a few minutes, so do the two changes in the same deploy.

Full reference: the /v1/auth/custom-token operation.

Clone this wiki locally