- 마지막 업데이트
기기 등록
이해하기
기기 등록은 이용자가 직접 지정한 모바일 기기에서만 게임 접속을 허용하거나, 특정 PC를 지정/관리하여 로그인 시 접근을 제한하는 보안 기능이에요.
| 항목 | 모바일 | PC |
|---|---|---|
| 이용 대상 | 정회원 전용 (게스트 계정 이용 불가) | 정회원 전용 / 국내 계정(가입 국가 기준)만 제공 |
| 기기 식별 방법 | 모바일 기기 고유 식별자(UDID, ADID) 기준으로 식별 | PC 기기 정보 수집 프로그램 설치 (제조업체, 제품명, 일련번호 수집 후 암호화 저장) |
| 기기 등록 수 제한 | 계정당, 게임별 최대 10대 등록 가능 (기본값 최대 5대, 변경 시 기술 담당자 요청) |
계정당 최대 5대 고정 |
| 인증 수단 | 보조 이메일 또는 휴대폰 점유인증 | 본인인증 |
| 탈퇴 시 처리 | 게임 해지 완료 시 해당 게임의 등록 기기 정보 자동 삭제 | 스토브 회원 탈퇴 완료 시 등록 정보 자동 삭제 (계정 전체 단위) ※ 개별 게임 해지는 지정 PC 설정에 영향 없음 |
적용 방식
모바일의 경우, 게임별 정책에 따라 기기 등록의 적용 강도를 선택할 수 있어요. 기기 등록 화면은 플랫폼 공통 UI로 제공돼요.
PC의 경우, 플랫폼 기본 기능으로 제공돼요. (별도 연동 작업은 하지 않아도 돼요.)
| 플랫폼 | 설정 | 목적 | 동작 방식 |
|---|---|---|---|
| 모바일 | 필수 설정 | 보안 최우선 |
|
| 선택 설정 | 사용성 고려 |
|
|
| PC | 플랫폼 기본 제공 |
|
모바일 환경의 적용 강도 변경은 기술 담당자에게 요청해 주세요
ㆍ 스토브 파트너스에서 설정해요.
ㆍ 선택형으로 운영하려면 기술 담당자에게 '선택 사용 설정' 작업을 별도로 요청해야 해요.
연동 가이드
사전 준비
| 항목 | 내용 | 비고 |
|---|---|---|
| 기기 등록 설정 요청 | 기술 담당자에게 필수/선택 설정 방식 요청 | 스토브 파트너스 |
| Mobile SDK 적용 | 기기 등록 팝업은 SDK에서 기본 제공. SDK 적용 필수 | SDK 설치 가이드 참고 |
| User Access Token 확인 | 이용자 로그인 후 SDK를 통해 획득한 토큰 필요 | 실시간 조회 필수 |
| API Access Token 확인 | 서버 간 통신을 위한 API Access Token 필요. 퍼블리싱 기술 담당자에게 요청 | 기술 담당자 요청 |
기본 연동 구조
기기 등록 기능은 스토브 Mobile SDK가 제공하는 플랫폼 공통 UI로 동작해요. CP사는 아래 영역을 구현해야 해요.
구현해야 할 영역
ㆍ 기기 등록 팝업 노출: 설정(필수/선택)에 따라 미등록 기기 이용자에게 등록 팝업을 노출해요.
ㆍ 등록 미완료 시 처리: 이용자가 등록을 취소하면 로그아웃 대신 재안내 UI로 등록을 다시 유도해요.
ㆍ 기기 관리 진입: 설정 화면 등에 기기 관리 버튼을 두고 기기 관리 기능을 호출해요.
ㆍ 서버 우회 방지 검증: 토큰 검증 시 기기 등록 여부를 함께 확인해 미등록·우회 접근을 차단해요.
ㆍ 등록 여부 기반 혜택(선택): 기기 등록 여부를 조회해 인게임 혜택 등에 활용해요.
기기 등록 팝업·다이얼로그 문구는 아래 예시를 참고해 주세요.
| 유형 | 문구 예시 (팝업/다이얼로그 문구) |
|---|---|
| 기본 안내형 | "기기 등록은 필수 절차입니다." "원활한 게임 이용을 위해 기기 등록을 완료해 주세요." |
| 보안 목적 강조형 | "계정 보호를 위해 기기 등록이 필요합니다." "기기 등록을 완료하신 후 게임을 이용하실 수 있습니다." |
| 이용자 설정 기반 안내형 | "기기 등록 사용 설정에 따라 기기 등록이 필요합니다." "계속 이용하시려면 기기 등록을 완료해 주세요." |
개발하기
모바일 SDK
기기 등록 팝업 노출과 인게임 기기 관리 UI는 모두 Auth/AuthUI 모듈이 자동으로 처리해요. 게임 클라이언트는 두 가지 진입점(AuthUI.Login, AuthUI.ManageDevices)만 호출하면 되고, 이용자 응답에 따른 후속 동선을 결과 콜백에서 처리해요.
MobileSDK가 자동 처리하는 영역 vs 게임 구현 영역
ㆍ SDK 자동: 기기 등록 화면 노출 시점·UI, 점유인증(이메일/휴대폰) 흐름, 등록된 기기 목록 화면
ㆍ 게임 구현: 인게임 설정 화면에 "기기 관리/등록" 버튼 배치, 노출 여부 판단, 결과 콜백 분기, 기기 등록 미완료(취소) 후속 동선
사전 준비
- 모듈:
Auth,AuthUI모듈을 적용해야 해요. SDK 설치는 SDK 다운로드 및 설치·개발 환경 설정 참고. - 선행 조건:
Auth.Initialize완료 후AuthUI.Login흐름을 사용 중이어야 해요. 기기 등록 화면이AuthUI.Login내부에서 자동 노출돼요. 로그인 흐름은 로그인 가이드 참고. - 권한·설정 값: 별도 단말 권한은 필요 없어요. 기기 등록 정책(필수/선택,
device_setup_exemption)은 SDK Config에서 기술 담당자가 설정해요. (위 연동 가이드 → 사전 준비 참고) - 의존 기능: 통합 로그인 UI(
AuthUI.Login) + 인게임 설정 화면 (기기 관리/등록 버튼 배치 위치)
개발 흐름
MobileSDK가 자동 처리하는 두 가지 진입점이에요. 게임에서는 각 진입점의 호출 시점과 결과 분기만 처리하면 돼요.
- 가입/로그인 시 —
AuthUI.Login에서 자동 노출- 게임이
AuthUI.Login()을 호출 (평소 로그인 흐름과 동일) - SDK가 이용자의 기기 등록 상태를 확인하고, 필요 시 기기 등록 화면을 자동으로 노출
- 필수 설정 정책 + 미등록 이용자 → 강제 노출
- 선택 설정 정책 → 등록 이력이 있는 계정이 미등록 기기로 접근할 때만 노출
- 이용자가 등록을 완료하면 콜백이
result.IsSuccessful로 반환 → 평소 로그인 후속 처리 진행 - 이용자가 등록을 완료하지 않고 화면을 닫으면 콜백이
result.IsCanceled로 반환 → 게임 정책에 따른 후속 동선 처리- 권장: 안내 UI 노출 후
AuthUI.Login재호출 (재호출하면 SDK가 기기 등록 화면을 다시 노출) - 로그아웃 처리는 이용자 이탈 위험이 있어 비권장
- 권장: 안내 UI 노출 후
- 게임이
- 인게임에서 —
AuthUI.ManageDevices호출- 인게임 설정 화면 등 적절한 위치에 기기 관리 / 기기 등록 버튼 배치
- 버튼 노출 여부는
Auth.AccessToken.User의 두 값으로 판단 (아래 표 참고) - 버튼 클릭 시
AuthUI.ManageDevices()호출 → SDK가 기기 등록·관리 화면을 자동으로 노출 - 콜백 결과는
Auth.AccessToken.User.VerifiedDevice값으로 분기true: 등록된 기기 → 게임 유지false: 미등록 기기 → 초기 화면 이동 후 재로그인 등 정책에 따른 후속 동선
버튼 노출 여부 — 판단 순서가 중요해요
- 먼저
deviceRegistrationPolicy(기기 등록 정책 사용 여부)를 확인 true인 경우에만verifiedDevice값으로 등록 완료 여부를 판단
| 기기 등록 상태 | deviceRegistrationPolicy | verifiedDevice | UI 처리 | 의미 |
|---|---|---|---|---|
| 등록 상태 | true | true | 기기 관리 버튼 노출 | 현재 접속 기기가 등록된 상태 |
| 미등록 상태 | true | false | 기기 등록 버튼 노출 | 현재 접속 기기가 미등록 상태 |
| 기능 Off | false | 항상 true | N/A | 기기 등록 사용 설정 Off 상태. 기술 담당자에게 요청 필요 |
트러블슈팅
| 상황 | 원인 | 처리 방안 |
|---|---|---|
AuthUI.Login 콜백이 result.IsCanceled로 반환됨 | 이용자가 기기 등록 화면을 닫고 등록을 완료하지 않음 | 안내 UI 노출 후 AuthUI.Login 재호출 권장. 로그아웃 처리는 이용자 이탈 위험이 있어 비권장. |
토큰 유효성 검증 시 46217 응답 발생 | 서버의 /token/verify 응답으로 받는 코드예요. 미등록 기기 또는 우회 접근으로 판단된 상태 | 클라이언트는 재로그인을 유도해 SDK 기기 등록 흐름이 다시 동작하도록 처리. 자세한 서버 처리는 위 Server 섹션 또는 연동 가이드 → 서버: 기기 등록 우회 방지 검증 참고. |
AuthUI.ManageDevices 호출 시 등록이 실패 | 동일 계정의 등록 기기가 정책 한도(기본 5대 / 게임별 최대 10대 / PC 5대 고정) 초과 | 이용자가 기존 기기 목록에서 일부를 삭제한 뒤 재등록하도록 안내. 게임별 등록 한도 변경은 기술 담당자에게 요청. |
| 기기 관리 버튼을 어떤 이용자에게 보여야 할지 판단이 안 됨 | deviceRegistrationPolicy 확인 없이 verifiedDevice만 참조 | 반드시 deviceRegistrationPolicy = true를 먼저 확인한 뒤 verifiedDevice로 버튼 라벨(관리/등록)을 결정. |
네트워크 일시 오류로 AuthUI.Login 실패 | result.IsServerError 또는 네트워크 오류 (com.stove.base.network 도메인) | OperationUI.HandleResult로 SDK 표준 오류 UI를 노출하고, 이용자 확인 후 재시도 흐름 제공. |
| 게스트 계정에서 기기 등록 화면이 안 뜸 | 모바일 기기 등록은 정회원 전용 기능 (게스트 계정 미지원) | 게스트 이용자에게는 기기 등록 안내 자체를 노출하지 않음. 정회원 가입 후 자동 노출됨. |
샘플 코드
AuthUI.Login과 AuthUI.ManageDevices 두 가지 진입점의 호출/콜백 처리 예시예요. 플랫폼별로 제공해요.
AuthUI.Login— 기기 등록 화면 자동 노출 처리
AuthUI.Login은 평소 로그인 호출과 동일해요. 콜백에서 result.IsCanceled 분기를 추가해 기기 등록 미완료 시 후속 동선만 처리하면 돼요.
AuthUI.Login의 전체 흐름은 로그인 가이드를 참고하세요
아래 예시는 기기 등록 처리에 필요한 부분만 발췌했어요.
public void Login()
{
AuthUI.Login((Result result, AccessToken accessToken) =>
{
if (result.IsSuccessful)
{
/** 로그인 성공 처리 ... (중략) **/
}
else if (result.IsCanceled)
{
/** 기기 등록 화면을 닫음(등록 미완료) → 게임 정책에 따라 처리 **/
/** 권장: 안내 UI 노출 후 Login() 재호출 → 기기 등록 화면 재노출 **/
}
else
{
/** 기타 오류 처리 ... (중략) **/
}
});
}
AuthUI.ManageDevices— 인게임 버튼 클릭 시 호출
인게임 설정 화면 등에서 "기기 관리/등록" 버튼 클릭 시 호출해요. 호출 후 Auth.AccessToken.User.VerifiedDevice 값으로 후속 동선을 분기해요.
public void ManageDevices()
{
if (Auth.AccessToken == null) return;
AuthUI.ManageDevices((Result result) =>
{
if (Auth.AccessToken.User.VerifiedDevice)
{
/** 등록된 기기 → 게임 유지 **/
}
else
{
/** 미등록 기기 → 기기 등록 유도 (예: 초기 화면 이동 후 로그인 재시도) **/
}
});
}
서버
POST /auth-secure/v1.0/my-device/{game_id}/check를 호출해 이용자의 기기 등록 여부와 보조 인증 수단(보조 이메일 인증·휴대폰 점유인증) 등록 여부를 조회하는 영역이에요. 인게임 혜택 지급 분기, 보조 인증 수단 확인 등의 용도로 사용해요.
우회 방지 검증과는 별개 API예요
미등록 기기 환경에서의 우회 접근 차단은 토큰 유효성 검증 API(POST /member/v3.0/{game_id}/token/verify)의 46217 응답으로 처리해요. (위 연동 가이드 → 서버: 기기 등록 우회 방지 검증 참고)
사전 준비
- API Access Token 발급이 선행돼야 해요. Authorization 헤더에
Bearer {API Access Token}형태로 사용해요. 발급 절차는 인증 메뉴 → Server 가이드를 참고하세요. - 클라이언트로부터 User Access Token을 매 요청마다 전달받는 구조여야 해요. 게임 서버에 캐싱하지 않아요.
개발 흐름
- 클라이언트가 게임 서버에 User Access Token을 전달해요.
- 게임 서버는 보유 중인 API Access Token의 잔여 유효기간을 확인하고, 필요 시 갱신해요.
POST /auth-secure/v1.0/my-device/{game_id}/check를 호출해요.- Path:
{game_id}에 게임 ID를 채워요. - Headers:
Authorization: Bearer {API Access Token},caller-id: {service_id}_SERVER,Content-Type: application/json - Body:
{ "access_token": "{User Access Token}" }
- Path:
- 응답
code에 따라 분기해요.code == 0→value.device_registered로 기기 등록 여부를 판단해요.true: 등록 완료 → 정상 진입 또는 인게임 혜택 지급false: 미등록 → 클라이언트의 기기 등록 동선 안내 (Mobile SDK가 자동 처리)
code != 0→ 트러블슈팅 표 참고
트러블슈팅
응답 code 별 처리 방안이에요. 상세 응답 코드·메시지 스펙은 API & SDK 레퍼런스 메뉴를 참고하세요.
| 응답 code | 상황 | 처리 방안 |
|---|---|---|
| 40000 | Authorization 헤더 누락·형식 오류 / User Access Token이 잘못되었거나 만료 / 요청 Body 오류 | 헤더 형식·Body 확인 후 재시도. User Access Token 만료라면 클라이언트에 재로그인을 유도하세요. |
| 40101 | API Access Token이 잘못됨 (Authorization 헤더 값 오류) | API Access Token을 재발급한 뒤 재시도하세요. |
| 40103 | API Access Token 또는 User Access Token 만료 | API Access Token이 만료된 경우 갱신 후 재시도, User Access Token이 만료된 경우 클라이언트에 재로그인을 유도하세요. |
| 41002 | 호출 path의 game_id와 보유한 API Access Token의 service_id가 다름 | 환경·게임별로 API Access Token을 분리해 발급·관리하세요. |
| 50000 | Unknown error | 일시적 오류일 수 있으니 재시도 후, 지속되면 기술 담당자를 통해서 문의주세요. |
샘플 코드
기기 등록 및 인증 정보 조회(POST /auth-secure/v1.0/my-device/{game_id}/check) 호출 예제예요.
Base URL은 환경(Live/Sandbox)에 맞춰 교체해 주세요
운영 환경에서는 하드코딩 대신 환경 변수(예: STOVE_API_BASE_URL)나 프레임워크 설정 파일로 분리해 환경별로 주입하는 것을 권장해요.
// 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()) {
String body = mapper.writeValueAsString(Map.of(
"access_token", userAccessToken));
HttpRequest req = HttpRequest.newBuilder(
URI.create(baseUrl + "/auth-secure/v1.0/my-device/" + serviceId + "/check"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiAccessToken)
.header("caller-id", callerId)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
JsonNode data = mapper.readTree(res.body());
if (data.path("code").asInt() != 0) {
// 트러블슈팅 표 참고 (40000 / 40101 / 40103 / 41002 등)
throw new IllegalStateException("device check failed: " + data.path("code"));
}
JsonNode value = data.path("value");
boolean deviceRegistered = value.path("device_registered").asBoolean();
if (deviceRegistered) {
// 기기 등록 완료 — 정상 진입 / 혜택 지급
} else {
// 기기 미등록 — 클라이언트의 기기 등록 동선 안내
}
}