JSON Web Tokens

JSON Web Tokens (JWT) are a standard for compact, URL-safe access tokens based on JSON. A SSO service acts as the certification authority: it signs the token with its private key, and any service that holds the SSO public key can verify the signature and trust the token’s contents.

A JWT carries user identity and, optionally, permissions at the time of issuance. Because permissions can change after the token is issued, services define a trust window, which is typically 5 minutes, and up to 24 hours for lower-risk access.


JWT Structure

Note

This section describes the GAP implementation, not the JWT standard.

A JWT consists of three parts separated by dots (.): header, payload, and signature. Each part is URI-safe Base64 encoded.



Payload

Contains user identity, metadata, and optional data fields. The three standard fields present in every token are:

iss required

Token issuer: the app_id (project number) of the issuing service.

iat required

UNIX timestamp of token issuance.

exp required

UNIX timestamp of token expiration.

Additional fields are described in Payload Fields.


Signature

Verifies that the token was issued by the SSO and has not been modified. Validate the signature using the SSO public key, retrieved using kid. See Get Token Publisher Public Key.


Payload Fields

The decoded payload may contain the following fields.

JWT payload example
{
  "uid": "1234567890",
  "iss": "1",
  "iat": 1691030400,
  "exp": 1704096000,
  "slt": "dX52ja9w",
  "kid": "b81a1cf283b24ab1a34c57a99c9de7e00b615ff1",
  "fac": "a6b913f0c9679b9f8b9d0f5fdf9fa877e69b9ec2dba13f052b0ecb32c1bbf8ff",
  "loc": "b7462f9e2341c23fc9b58f7e618fc9b674f2e5fe7c0f73e80946c54d6a762bb",
  "auth": "login",
  "lng": "en",
  "cntry": "US",
  "tgs": "email_verified,lang_en,partner_organic",
  "aud": "1",
  "perm": ["read", "write"],
  "rev": 1,
  "pub_key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzZ5q88I47v8dsF5Vvlww",
  "fip": ["192.168.0.0/32", "10.0.0.0/32"],
  "links": {"steam_id": "76561198012345678", "psn_id": "user_psn_id"},
  "prem": "live",
  "app": [1, 2, 3],
  "env": ["test", "prod"],
  "app_perm": 1,
  "svc": "1"
}

Core

uid string required

User ID.

iss string required

Application ID of the issuer service. For SSO, this is "1".

iat integer required

UNIX timestamp of when the token was issued.

exp integer required

UNIX timestamp of when the token expires.

slt string required

Random salt used for hash calculation.

kid string required

Key ID identifying the public key used to verify the token signature.


Hash Fields

One of the following groups is always present:

fac string conditionally required

SHA-256 hash of the device factor used during login: sha256(factor + slt).

loc string conditionally required

SHA-256 hash of geolocation data based on the login IP address: sha256(loc + slt). Present when the IP address is available.

hash string conditionally required

MD5 hash of uid + slt. Present as an alternative to fac/loc when factor-based hashing is not used.


User Profile

nick string optional

User nickname.

tgs string optional

Comma-separated list of user tags (e.g., "email_verified,lang_en").

auth string optional

Authorization type as returned by the Auth service (e.g., "login").

lng string optional

Language code (e.g., "en").

cntry string optional

Country code as returned by the Auth service (e.g., "US").

prem string optional

Premium subscription flag for PlayStation Network or Xbox Live. Possible values: "psn", "live". Corresponds to psn_plus or live_premium in the Auth service response.

links object optional

Map of external platform associations. Keys are platform-specific identifiers: psn_id, dmm_id, steam_id, goodgames_id, gamecenter_id, nintendo_id, live_xuid, live_id, epic_id, google_id. Only keys present in the Auth service response are included.

rev integer optional

Token revision number. If omitted, defaults to 0.

typ string optional

Custom token type.


Permissions

aud string optional

Internal ID of the target application in the permissions system. Included in tokens issued via the control panel.

prj string optional

Project ID the application belongs to.

als array optional

List of project aliases.

app_perm integer optional

Internal application ID in the permissions system, used to fetch the permission set.

perm array optional

List of user permissions.

app array optional

List of external application IDs.

env array optional

List of supported environments (e.g., ["test", "prod"]).


Other

fip array optional

List of IP networks in CIDR format for which the token is valid. Used to match against the requestor’s IP address.

pub_key string optional

Public key used to verify request signatures in certain API requests.

svc string optional

Service account flag. Present with value "1" when the token belongs to a service account; absent for regular user tokens.

src string optional

Source or circuit identifier.

pxu string optional

External user ID.

Note

Additional custom fields may be present depending on the flags specified in the JWT request.


Types of JWT

Custom Tokens

  • Bound token: Issued during user authorization and bound to a specific application. Grants access to user permissions.

  • Unbound token: A temporary, one-time token derived from a bound token. Not bound to any application; used to transfer authentication to another application — for example, a launcher authenticating multiple apps after login. Attempting to exchange an unbound token more than once returns an error.

Service Tokens

  • Generated service JWT: Created dynamically per request and signed with a private key. The private key for your service (along with the SSO public key) is available via DevOps team. This token can be safely exposed on the client side.

    A generated service token contains three fields:

    iss

    The token issuer.

    iat

    Issuance timestamp.

    exp

    Expiration timestamp. Keep this short, typically 3–5 minutes.

  • Predefined service JWT: A manually created token for a specific application (contact WebDev team for details). Do not expose this token on the client side.


Retrieve Custom JWT

In most cases, a JWT is returned automatically for all successful authorization requests. In some scenarios you may need to explicitly pass a flag to request a JWT (check the login method documentation for details).

When retrieving data from the SSO using a refresh token, the response includes:

jwt

The user token with access rights.

factor

The device identifier used during login, required for permission-related operations.

To verify the token signature, retrieve the current public key using the kid from the JWT header. See Get Token Publisher Public Key.


Token Verification Workflow

  1. Read the header and confirm the token is JWT.

  2. Extract kid from the header.

  3. Use kid to retrieve the public key.

  4. Verify the signature using the public key and algorithm.

  5. If the signature is valid, decode the token and extract the payload.

Example Token

Header:

{
  "alg": "RS256",
  "kid": "381476",
  "typ": "JWT"
}

Payload:

{
  "auth": "login",
  "cntry": "GE",
  "exp": 1703691169,
  "fac": "0b3bf238875dbbcc732d7dbf19c10874d77cdd9e44bd6e2c9bb6965a90a6bbfc",
  "iat": 1695915169,
  "iss": "1",
  "kid": "381476",
  "lng": "ru",
  "loc": "357acf93a26fd2ada0a2853d8d669e04b0feb0315761d8d351da1f2ee913c1dc",
  "nick": "someUserName",
  "slt": "GBgBHnro",
  "tgs": "email_verified,lang_ge,partner_organic,player_el,player_wt,sso_allowed_post,wt_first_login,wt_ge",
  "uid": "133292415"
}

The token may include additional custom fields depending on the flags passed in the JWT request.


Retrieve Permissions

To retrieve the user’s permissions, see Retrieve and Edit User Schema.

See also

For more information on managing permissions, see Roles and Permissions Management.


Transfer Unbound Tokens Between Applications

  1. Application A authorizes the user and obtains a bound token.

  2. Using the bound token, Application A requests an unbound token.

  3. Application A transfers the unbound token to Application B.

  4. Application B exchanges the unbound token for a bound token.

Note

If Application B receives the error “Token has already been used” when exchanging the unbound token, revoke the bound token associated with it (see Revoke Token). This error indicates the unbound token may have been compromised.

As a best practice, Application B should notify Application A of the outcome.


Unbound Token APIs

Retrieve Unbound Token

POST https://login.gaijin.net/api/sso/temporaryJwt

Request

  • jwt string required

    The bound token for which a one-time token is issued.

  • factor string required

    The device identifier used at login.

Request example
jwt=XXXXX&factor=YYYYY

Response

Success

  • status string required

    • “OK”

  • jwt string required

    The one-time unbound token.

Response example
{
  "status": "OK",
  "jwt": "XXXXXX"
}

Error

  • status string required

    • “LOGINERROR”

  • error string required

    • “Wrong token format”

      Token parsing error.

    • “Token rejected”

      Token has been revoked.

    • “Wrong token”

      Token expired or not confirmed.

    • “Generate token error”

      Internal error while generating a temporary token.

Response example
{
  "status": "LOGINERROR",
  "error": "Wrong token"
}

Exchange Unbound Token for Bound Token

POST https://login.gaijin.net/api/sso/securityJwt

Request

  • jwt string required

    The unbound token.

Request example
jwt=XXXXX

Response

Success

  • status string required

    • “OK”

  • jwt string required

    The bound token.

  • factor string required

    The device factor associated with the token.

Response example
{
  "status": "OK",
  "jwt": "XXXXX",
  "factor": "YYYYY"
}

Error

  • status string required

    • “LOGINERROR”

  • error string required

    • “Wrong token format”

      Token parsing error.

    • “Token expired”

      Token expired.

    • “Wrong token”

      Token expired or not confirmed.

    • “Generate token error, deactive temporary”

      Failed to mark the token as used.

    • “Generate token error”

      Internal error generating a temporary token.

    • “Token has already been used”

      Token has already been used.

Response example
{
  "status": "LOGINERROR",
  "error": "Token has already been used"
}

Revoke Token Associated with Unbound Token

POST https://login.gaijin.net/api/sso/rejectJwt

Request

  • jwt string required

    The user’s bound token.

  • cleanjwt string required

    The corresponding unbound (temporary) token.

Request example
jwt=XXXXX&cleanjwt=YYYYY

Response

Success

  • status string required

    • “OK”

Response example
{
  "status": "OK"
}

Error

  • status string required

    • “LOGINERROR”

  • error string required

    • “Wrong token format”

      Token parsing error.

    • “Token rejected”

      The bound token has already been revoked.

    • “Wrong token”

      Token expired or not confirmed.

    • “Wrong temporary token”

      The unbound token has expired or not been confirmed.

    • “Token expired”

      Token expired or not confirmed.

    • “Cannot self ban”

      Cannot revoke a token issued by the current temporary token.

Response example
{
  "status": "LOGINERROR",
  "error": "Wrong token"
}

JWT Security

Anyone who obtains a valid token can use it to execute requests on behalf of the user it was issued to. Token theft is always a security risk, especially when the token belongs to a developer or administrator.

JWT with Fixed Audience

A JWT can include the aud field, which contains the target application ID. When present, the system validates that the aud value matches the target application ID in the request. If they do not match, the request is rejected.

This ensures that a token issued for one application cannot be used to access another.

Example:

// CheckJwtAudience checks if JWT aud claim is valid for target application.
func CheckJwtAudience(jwt jwt.JWT, targetAppID int) error {
	if audience := jwt.Claims().Get("aud"); audience == nil || targetAppID == 0 || audience == strconv.Itoa(targetAppID) {
		return nil
	}

	return ErrInvalidAudience
}

Factor-Based Device Binding

A JWT stores a hash of the factor — a random value generated at login time and stored in the browser. The token does not store the factor directly; the fac claim contains sha256(factor + slt).

Because only the original browser holds the factor, the token can only be used from that browser. Even if the token is stolen, it cannot be used from a different browser without the factor.

Limitations

Factor-based binding does not work well for automated or server-side workflows. For example, a build system that makes repeated API calls – such as uploading builds – cannot interactively log in each time to obtain a factor. In these cases, logging in without a factor is required, which reduces security.

A practical alternative for server-side scenarios is to restrict the token by IP address instead.

IP Address Restriction

To reduce the risk of token theft, you can bind a token to the IP address used at login. If someone attempts to use the token from a different IP address, the request is rejected with a 403 error.

To request an IP-bound token, include the following parameter when logging in:

fixed_ip=1

The server records the login IP address in the token’s fip claim. The token will only be accepted from that address.

Note

IP-bound tokens are most useful for protecting developer and administrator accounts that work with Central and other GAP tools. They are not recommended for player-facing tokens, since players’ IP addresses change frequently.

Scenario 1: Persistent CLI Token

You need a token for repeated command-line operations without logging in each time. Generate a token with fixed_ip=1, save it to disk, and reuse it. If your IP address changes, generate a new token.

A service that supports JWT authorization can indicate that the token should be bound to the current IP address. If the returned token contains an fip claim, it is safe to save to disk. If the returned token does not include an IP address, or if a bound token was requested but a regular one was returned, do not save it.

Scenario 2: CI/Build System Token

You need a token for a server-side system – for example, a CI pipeline that builds and uploads game versions to GDN. Create a service account for the build system and generate a token with the fixed IP address (or IP range) of the server.

Note

Make sure the server has a static IP address. If the server uses a dynamic IP address – for example, in containers that are recreated frequently – this method is not applicable.

IP networks are stored in the fip claim in CIDR format:

{
  "fip": [
    "124.56.48.12/30",
    "127.0.0.1/16",
    "57.234.44.15/32"
  ]
}

See also

For more information on CIDR format, see Classless Inter-Domain Routing.