- Last Updated
Authentication (Tokens & Validation)
Understanding
STOVE authentication is the procedure that proves identity so that the game client, game server, and web services can safely use STOVE platform user information. By integrating authentication, you can receive the authentication info of users logged in with a STOVE account—without building your own membership system—and use it for all services that require authentication, such as game entry, API calls, payment, and sanction handling.
Components of Authentication
STOVE authentication operates via two main paths depending on the authenticating party.
| Path | Authenticating party | Platform used | Issued token |
|---|---|---|---|
| User authentication | Each logged-in user | Mobile SDK, PC SDK, Web | User Access Token, Refresh Token |
| Server authentication | Game server (system) | Server | API Access Token |
Understanding the two authentication paths
ㅁ User authentication: the SDK/web module handles STOVE login and issues a User Access Token.
ㅁ Server authentication: the game server obtains an API Access Token with client_id/client_secret and uses it for API calls.
ㅁ The two tokens have different roles and can't substitute for each other. When validating a user token, the game server also uses its own API Access Token.
Authentication Flow Paths by Platform
The authentication flow path and the tools used differ by the platform the game launches on (Mobile/PC/Web/Server).
Integrate only the areas you need, matching your game's launch form.
| Platform | Integration tools | Obtained info | Main use |
|---|---|---|---|
| Mobile | Mobile SDK (Android/iOS/Unity/Unreal) | User Access Token, member identifier (guid or member_no) |
Mobile game login and game-server authentication |
| PC | PC SDK (PCSDK3) + STOVE PC Client | User Access Token, member identifier (guid or member_no) |
PC game execution authentication and game-server authentication |
| Web | STOVE Web authentication (GNB method or login URL method) |
SUAT (cookie-based Web Access Token) |
Login integration for the game's official homepage and event pages |
| Server | STOVE Platform API (Server-to-Server) |
API Access Token | Backend API calls such as user-token validation, sanction lookup, and member-info lookup |
Notes on platform integration
ㅁ Multi-platform games integrate the areas they need together, such as Mobile + PC + Server.
ㅁ If there's any flow where the game server calls the STOVE API, Server authentication is required regardless of platform.
Token Types and Roles
STOVE issues three main kinds of tokens, each with a different role and expiry time.
| Token Type | How to obtain | Role | Validity |
|---|---|---|---|
| User access token (User Access Token) |
SDK | Issued on successful user login. Used for user authentication and proof of authority. Short validity for security—valid for only 6 hours. |
6 hours (21600000ms) |
| Refresh token (Refresh Token) |
– | Used to reissue when the user access token expires. Allows renewing the access token without separate authentication for a certain period. Auto-renewed inside the SDK. Take care not to use this token directly. |
720 hours (30 days) |
| Platform API access token (API Access Token) |
API | Used as the authentication method when calling STOVE-provided APIs. Long validity; must be reissued after expiry. |
720 hours (30 days) |
Token Usage Policy
These are usage principles that all environments must follow in common, regardless of token type.
| Principle | Description |
|---|---|
| Do not cache the User Access Token | Valid for only 6 hours after issuance. Can change due to the user's re-login, refresh, logout, etc. Always look it up in real time via the SDK when needed. |
| Auto-renewal is handled by the SDK | The SDK auto-renews with the Refresh Token at 80% of the expiry time. Do not handle the Refresh Token directly in game code. |
| Manage the API Access Token only on the server | For server-to-server authentication, valid for 30 days. Do not expose it to the client, external systems, or logs. Store expires_in to renew before expiry, or keep it current by calling periodically 1–2 times a day. |
| The game server must not persist user tokens | The client passes the User Access Token with each request, and the game server calls the validation API with that token. |
Game Identifiers Summary
The game-identifier terms used in STOVE authentication and APIs are below.
The standard identifier is Game ID (string).
| Term | Description | Notes |
|---|---|---|
| Game ID | A unique string that identifies the game. Stays the same regardless of environment (Sandbox/Live). |
The standard identifier officially provided by the sanction API and others. |
| Game No | A numeric code assigned to distinguish games. | Not used in current integration. Use Game ID as the identifier. |
| Service ID | An ambiguous term where Game No and Game ID are used interchangeably. | Ambiguous, so not used. |
- The member identification number inside the STOVE platform is
member_no(numeric). - Currently integrated games receive
guidas the member identifier.
Authentication Add-on Features
These are add-on features the STOVE authentication system provides in addition to basic authentication.
| Feature | Supported platforms | Description |
|---|---|---|
| Email verification | Mobile SDK | Confirms identity by sending a verification code/link to the account's email. Mobile email-account verification is required from SDK 2.8.0. STOVE email accounts use the sign-up email; 3rd-party accounts use the secondary email set in 'My Info'. |
| Web authentication (GNB / login URL) | Web | Uses STOVE login on websites. The GNB method (recommended) provides a responsive GNB UI module; the login URL method links directly to the STOVE login page. Available on the xxx.game.onstove.com domain. |
| Member sanction-status lookup | Server | The game server queries the STOVE API for a member's platform-sanction, game-sanction, and posting-sanction status. Even when multiple sanctions exist, it responds with a single code by priority. |
Integration Guide
Platform-specific Prerequisites
Depending on your game's launch form, you only need to do the prerequisites for the platforms you need.
| Platform | Required items |
|---|---|
| Mobile | ㅁ Download the Mobile SDK and apply it to the project ㅁ Set App ID / Client ID ㅁ Register the package/bundle ID for iOS and Android separately |
| PC | ㅁ Download the PC SDK (PCSDK3) and apply it to the project ㅁ Set App ID / Client ID ㅁ Verify the game-execution path via the STOVE PC Client (launcher) |
| Server | ㅁ Request the API Access Token issuance keys ㅁ Provide the Game ID to the publishing technical contact to have client_id, client_secret, and service_id issuedㅁ Issued separately per service environment (Live, Sandbox) |
| Web | ㅁ Usable only when the integrated web service domain is xxx.game.onstove.comㅁ The fourth-level domain connection is applied through the technical PM ㅁ An SSL certificate must be issued when using external infrastructure ㅁ Inflow-path codes such as inflow_path are also issued through the technical PM |
Environment-separated issuance is required
Always issue keys and tokens separately per environment (Live/Sandbox) and don't mix them.
Mixing environments causes 40105 (client_id/client_secret mismatch) or 41002 (service_id mismatch) errors in the validation API.
Full Authentication Flow
Even across platforms (Mobile/PC/Web), the order in which authentication proceeds is the same. They all follow the 5 steps below, and only the concrete way to implement each step differs by platform.
| Step | Task | Actor | Description |
|---|---|---|---|
| 1 | User login | Client (SDK/Web) | Performs STOVE login via the SDK/web module. Issues a User Access Token on success. |
| 2 | Look up the User Access Token | Client | Look up the latest token via the SDK API each time you use it. No caching. |
| 3 | Pass the token to the server | Client → game server | Pass the User Access Token to the game server when an API call is needed. |
| 4 | Issue/renew the API Access Token | Game server ↔ STOVE | The game server issues/renews the API Access Token with client_id/client_secret. |
| 5 | Validation and branching | Game server ↔ STOVE | Validates the User Access Token via the STOVE validation API. Branches into normal entry, re-login prompt, or access block based on the response code. |
Call the validation API only from the game server
Calling it directly from the client exposes the API Access Token and creates a security problem.
Perform validation on the game server, and the client only receives the result.
Environment Distinction Guide
STOVE provides two environments, Sandbox and Live, to separate the development stage from the operations stage.
Key issuance, domains, and the validation API are all operated separately per environment, so be careful not to mix them.
| Category | Use | When to use |
|---|---|---|
| Sandbox | Development/test environment | SDK integration verification, checking response codes per scenario, QA. Not exposed to real users. |
| Live | Commercial service environment | Service for real users. Even after launch, verify new features in Sandbox first, then apply to Live. |
- Issue
client_id,client_secret, andservice_idseparately per environment. - If the validation API's
game_iddiffers from theservice_idof the API Access Token you hold, a41002error occurs. Manage them separately per environment and game.
Development
Mobile
Prerequisites
- The call to
Auth.login(Android) /[SGSAuth login](iOS) /Auth.Login(Unity/Unreal) must be complete. When not logged in,accessTokenreturnsnull. - Don't cache the token on the client; re-fetch it from the SDK each time you use it. Since the SDK auto-renews at 80% of the expiry time, the value fetched from the SDK is always the latest.
- Auto-renewal works only while the app process is running. If the process is terminated in the background, renewal stops, so on returning to the foreground, verify the call result and, if expired, guide the user into the re-login flow.
- Even when you need to pass the token to the game server, don't store it on the server side; pass it along each time a client call occurs.
Development Flow
- The game client looks up the latest AccessToken via a per-platform API such as
Auth.accessToken?.token(Kotlin) /[[SGSAuth accessToken] token](iOS). - If the return value is
null, the user is not logged in or has logged out, so guide them into the login flow. - If you need to pass the token to the game server, pass the token received from the SDK at call time as-is. Don't store it on the server side; receive it anew with each request.
- The game server validates the token with the STOVE platform's Game User Access Token validation API, then branches into normal entry, re-login prompt, access block, etc. (See the game-server guide for the validation API)
Auto-renewal proceeds in the following sequence:
Troubleshooting
Don't cache the AccessToken
Since the SDK auto-renews at 80% of the expiry time, calling Auth.accessToken each time guarantees the latest value. Reusing a token stored on the client or game server causes authentication errors from a token invalidated after expiry/renewal.
| Situation | Cause | Action |
|---|---|---|
accessToken returns null | Not logged in, or just after logout | Check Auth.accessToken != null before calling, and if null, guide the user into the login flow. |
| 401 authentication failure on API call (expired token) | The token expired without auto-renewal running (e.g., returning after a long background) | Re-fetch Auth.accessToken each time you use it to get the latest token. If it's still expired, prompt re-login. |
| Failure when calling with a token stored on the game server | The token was invalidated by the client's re-login, logout, or auto-renewal | The game server should not persist the token; use the latest token received with the client request to call the STOVE validation API. |
| Auto-renewal doesn't run | The app process was terminated in the background, halting the SDK callback | Re-fetch the token on returning to the foreground (onResume / applicationDidBecomeActive), and prompt re-login if expired. |
Sample Code
public void GetToken()
{
string token = Auth.AccessToken.Token;
}
PC (PCSDK)
Prerequisites
- BaseSDK initialization (
Base_RestartAppIfNecessaryAsync→Base_InitializeEx) and login completion must come first. Calling before initialization returnsBASE_NOT_INITIALIZED(16). - Pre-allocate a sufficiently large buffer to receive the AccessToken. If the length is insufficient,
INVALID_PARAM(5) may be returned. - The
client_id/client_secret/service_idfor API Access Token issuance must be held by the game server and must not be exposed to the client. - Don't cache the token; re-fetch it via the SDK when needed. It can be invalidated at any time by the user's re-login, logout, or session change.
Development Flow
- The game client calls
Base_GetAccessToken(buffer, length)to get the latest User Access Token. - Validate the returned result (
Result) withIsSuccessful(). (Both C/C++ and C# useresult.IsSuccessful()) - If the token needs to be used on the game server, the client passes it to the game server. Don't store it on the server side; receive and pass it again at call time.
- The game server calls the STOVE platform's Game User Access Token validation API to perform a secondary validation of the token. This requires the API Access Token in the Authorization header.
- Branch the follow-up handling—normal entry, re-login prompt, access block, etc.—based on the validation response code.
Troubleshooting
| Situation | Cause | Solution |
|---|---|---|
Calling Base_GetAccessToken right after game start returns BASE_NOT_INITIALIZED (16) | Base_RestartAppIfNecessaryAsync is async, so initialization isn't complete before the callback arrives. Initialization completes only when Base_InitializeEx is called in the callback's restartAppIfNecessary == false branch; fetching the token before that causes error 16. | In the Base_RestartAppIfNecessaryAsync callback, confirm restartAppIfNecessary == false, call Base_InitializeEx, and only look up the token after initialization succeeds. Typically, finish initialization before entering the title screen and look up the token after the login step. |
A server call after the user has played for a while returns INVALID_ACCESS_TOKEN (19) | Base_GetAccessToken returns the latest token on every call, so error 19 doesn't occur in a normal environment. If it does, the cause is a temporary network failure or an abnormal SDK state. | If 19 is returned, don't continue the game; show "Please restart via the STOVE PC Client" and then exit the game. Don't cache the token in a member variable; fetch it with Base_GetAccessToken right before each game-server call to avoid issues. |
The token string is truncated, or INVALID_PARAM (5) is returned | The token length is variable and may grow in the future, so a small buffer (e.g., 256/1024 bytes) is insufficient. | Allocate and pass a wchar_t buffer of size 4096. Don't process the received token by length; send it to the game server as-is to avoid issues. |
FAIL (1) is returned | Base_GetAccessToken is a local cache lookup and involves no communication, so error 1 doesn't occur in a normal environment. If it does, the cause is an abnormal internal SDK state (memory corruption, missing token actor, etc.). | As with 19, don't continue the game; show "Please restart via the STOVE PC Client" and then exit the game. |
You must not cache the User Access Token
It's valid for only 6 hours after issuance and changes at any time due to the user's re-login or logout. Server-side storage or client caching causes authentication errors from expired/changed tokens. Always get the latest value with Base_GetAccessToken each time you use it.
Manage the API Access Token only on the game server
It's a server-to-server authentication token valid for 30 days, so it must not be exposed to the client. The game server issues it with client_id/client_secret and renews it based on expires_in. If the existing token has 30% or more validity remaining, the same token is issued; if less, a new token is issued.
Sample Code
// Assumes Base_RunCallback() is registered to be called in the game loop.
constexpr uint32_t kTokenBufferSize = 4096;
wchar_t accessToken[kTokenBufferSize] = { 0 };
auto result = Stove::PCSDK::Base::Base_GetAccessToken(accessToken, kTokenBufferSize);
if (result.IsSuccessful())
{
// Send the accessToken string to the game server to perform validation.
}
else
{
// Implement the failure logic (prompt re-login, user guidance, etc.).
}
Server
Prerequisites
- The game server must hold
client_id/client_secret/service_id.
For the issuance procedure and environment (Live/Sandbox) separation, see 2. Integration Guide → Token Issuance Prerequisites above. - The structure must receive the Game User Access Token from the client with each request. Don't cache it on the game server.
Development Flow
- The client passes the Game User Access Token to the game server.
- The game server checks the remaining validity of the API Access Token it holds. (Based on the
expires_inreceived at issuance) - If there's no token or less than 30% remaining, call
POST /auth/v5/server_tokento issue/renew the API Access Token.
If 30% or more remains, the same token is returned, so you can use the response'saccess_tokenas-is. - Call
POST /member/v3.0/{game_id}/token/verifyto validate the Game User Access Token received from the client.
PutBearer {API Access Token}in the Authorization header. - Branch based on the response
code: normal entry (code == 0), re-login prompt, device-registration prompt, access block, etc.
Identify the user by the responsevalue.guid(GUID-based games) orvalue.member_no.
Troubleshooting
These are handling approaches per response code. For the detailed response-code and message spec, see the API & SDK Reference menu.
| Response code | Situation | Handling approach |
|---|---|---|
| 40000 | The Game User Access Token is invalid or expired, or the request body is wrong | Prompt the client to re-login, and verify the request body is correct. |
| 40101 | The API Access Token is invalid (wrong Authorization header value) | Reissue the API Access Token and retry. |
| 40103 | The API Access Token expired | Call POST /auth/v5/server_token to renew it, then retry. |
| 40105 | client_id / client_secret mismatch when calling the issuance API | Check that you aren't mixing keys across environments (Live/Sandbox). |
| 41002 | The game_id in the validation API path differs from the service_id of the API Access Token you hold | Issue and manage the API Access Token separately per environment and game. |
| 46217 | (Mobile device-registration games only) A registered member with an unregistered device | Guide the client into the device-registration flow. Doesn't occur when validating with a token obtained in the PC SDK environment. |
| 50000 | Unknown error | It may be a temporary error, so retry; if it persists, inquire through the technical PM. |
The API Access Token must not be exposed outside the game server
Be careful not to print it to the client, external systems, or logs. If exposed, reissue it immediately.
Use instance_id to separate token lifetimes across multiple server instances
If you don't specify instance_id, the same token is issued to all servers based on client_id.
If you want to separate issuance/renewal cycles per instance, pass instance_id with the issuance request.
Sample Code
Examples of calling API Access Token issuance (POST /auth/v5/server_token) and Game User Access Token validation (POST /member/v3.0/{game_id}/token/verify).
Replace the Base URL to match the environment (Live/Sandbox)
In production, instead of hardcoding, we recommend separating it into an environment variable (e.g., STOVE_API_BASE_URL) or a framework config file and injecting it per environment.
// Java 25 LTS — java.net.http.HttpClient + Jackson(ObjectMapper)
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
ObjectMapper mapper = new ObjectMapper();
String baseUrl = "https://api.onstove.com";
String serviceId = "STOVE_GAME";
String callerId = serviceId + "_SERVER";
try (HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.build()) {
// 1) Issue the API Access Token
String issueBody = mapper.writeValueAsString(Map.of(
"client_id", "com.stove.stovegame.clientid",
"client_secret", clientSecret,
"service_id", serviceId,
"instance_id", "server001"));
HttpRequest issueReq = HttpRequest.newBuilder(URI.create(baseUrl + "/auth/v5/server_token"))
.header("Content-Type", "application/json")
.header("caller-id", callerId)
.POST(HttpRequest.BodyPublishers.ofString(issueBody))
.build();
HttpResponse<String> issueRes = client.send(issueReq, HttpResponse.BodyHandlers.ofString());
JsonNode issueData = mapper.readTree(issueRes.body());
if (issueData.path("code").asInt() != 0) {
// See the troubleshooting table (40105, etc.)
throw new IllegalStateException("Token issue failed: " + issueData.path("code"));
}
String apiAccessToken = issueData.path("response_data").path("access_token").asText();
// 2) Validate the Game User Access Token
String verifyBody = mapper.writeValueAsString(Map.of(
"access_token", gameUserAccessToken));
HttpRequest verifyReq = HttpRequest.newBuilder(
URI.create(baseUrl + "/member/v3.0/" + serviceId + "/token/verify"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiAccessToken)
.header("caller-id", callerId)
.POST(HttpRequest.BodyPublishers.ofString(verifyBody))
.build();
HttpResponse<String> verifyRes = client.send(verifyReq, HttpResponse.BodyHandlers.ofString());
JsonNode verifyData = mapper.readTree(verifyRes.body());
if (verifyData.path("code").asInt() == 0) {
JsonNode value = verifyData.path("value");
// Identify the user by value.path("guid").asLong() or value.path("member_no").asLong()
} else {
// See the troubleshooting table (40000 / 40101 / 41002 / 46217, etc.)
}
}