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.
Header
Contains metadata about the token and the cryptographic algorithm used (typically HMAC SHA-256 or RSA):
- alg required
Signing algorithm. SSO uses RS256.
- kid required
Public key ID used for signature verification. See Get Token Publisher Public Key.
- typ optional
Token type. Always
"JWT".
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.
{
"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 tofac/locwhen 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 topsn_plusorlive_premiumin 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:
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
Read the header and confirm the token is JWT.
Extract
kidfrom the header.Use
kidto retrieve the public key.Verify the signature using the public key and algorithm.
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
Application A authorizes the user and obtains a bound token.
Using the bound token, Application A requests an unbound token.
Application A transfers the unbound token to Application B.
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
Response
Success
Error
{
"status": "LOGINERROR",
"error": "Wrong token"
}
Exchange Unbound Token for Bound Token
POST https://login.gaijin.net/api/sso/securityJwt
Request
Response
Success
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.
{
"status": "LOGINERROR",
"error": "Token has already been used"
}
Revoke Token Associated with Unbound Token
POST https://login.gaijin.net/api/sso/rejectJwt
Request
Response
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.
{
"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.