REST API
페타믹스 API의 모든 엔드포인트, 인증 방법, 오류 코드에 대한 상세한 문서입니다.
API 개요
라이브 환경
- Base URL: https://dev-api.fetamix.com/api/v1
- 인증 방식: Bearer Token (JWT)
- 응답 형식: JSON
- 문자 인코딩: UTF-8
샌드박스 환경
- Base URL: https://dev-api-sandbox.fetamix.com/api/v1
- 사이트 URL: https://dev-sandbox.fetamix.com
- 인증 방식: Bearer Token (JWT)
- 응답 형식: JSON
인게임 인증 API
API 링크 요약
라이브 환경
- 인게임 로그인 시작(웹 경로):https://dev.fetamix.com:8081/ingame-login?client_secret=YOUR_CLIENT_SECRET&key=DEVICE_KEY&client=game
- 토큰 유효성 검증(API):GET https://dev-api.fetamix.com/api/v1/game/auth/verify
샌드박스 환경
- 인게임 로그인 시작(웹 경로):https://dev-sandbox.fetamix.com:9090/ingame-login?client_secret=YOUR_CLIENT_SECRET&key=DEVICE_KEY&sandbox_game_id=SANDBOX_GAME_ID
- 토큰 유효성 검증(API):GET https://dev-api-sandbox.fetamix.com/api/v1/game/auth/verify
인게임 토큰 페이로드
인게임 로그인 완료 시 발급되는 JWT의 페이로드는 아래와 같습니다.
예시
{
"sub": 1,
"type": "app",
"game_id": 1,
"device_key": "android_abcdef-1234-...",
"iat": 1761714925
}필드 설명
sub: 사용자 ID (number)type: 고정값"app"game_id: 게임 식별자 (number)device_key: 기기 식별자(예: Android 디바이스 ID)iat: 발급시각(Unix epoch, seconds). 만료(exp)는 포함되지 않음
OAuth 인증 (최초 로그인)
신규 설치 또는 토큰이 없는 경우에만 사용됩니다. 인게임에서 토큰이 없을 때 외부 브라우저에서 로그인 페이지로 이동합니다. client 파라미터로 인게임임을 구분합니다.
외부 브라우저에서 열기
라이브 환경:
https://dev.fetamix.com:8081/ingame-login?client_secret=YOUR_CLIENT_SECRET&key=DEVICE_KEY&client=game
샌드박스 환경:
https://dev-sandbox.fetamix.com:9090/ingame-login?client_secret=YOUR_CLIENT_SECRET&key=DEVICE_KEY&sandbox_game_id=SANDBOX_GAME_ID
로그인 완료 후 딥링크 스킴으로 인증 데이터와 함께 Unity 앱으로 리다이렉트됩니다.client_secret 파라미터에는 게임 발급시 부여 받은 시크릿키를 입력합니다.key 파라미터에는 기기 고유 정보가 포함됩니다. (예: Android 디바이스 ID)
샌드박스 환경에서는 sandbox_game_id 파라미터가 필요합니다.
딥링크 스킴 예시
// Unity 앱에서 등록한 딥링크 스킴 (토큰만 전달) fetamix://ingame-login?token=JWT_TOKEN // JWT 토큰(type: "app")에 인게임 식별 정보가 포함됨
Unity에서 이 스킴을 처리하여 JWT 토큰을 받아 저장하세요. 게임 클라이언트는 토큰만 보관하면 됩니다.
인게임 로그인
이미 인증받은 토큰을 가지고 있는 클라이언트가 재실행될 때 사용됩니다. 게임 시작 시 토큰의 유효성을 확인하는 API입니다.
토큰 유효성 검증 API
라이브 환경:
GET https://dev-api.fetamix.com/api/v1/game/auth/verify Authorization: Bearer YOUR_ACCESS_TOKEN
샌드박스 환경:
GET https://dev-api-sandbox.fetamix.com/api/v1/game/auth/verify Authorization: Bearer YOUR_ACCESS_TOKEN
인게임은 URL 파라미터 없이 저장된 JWT로 유효성만 확인하면 충분합니다. 서버는 device_key 일치 여부도 검사합니다. 실패(401 또는 기기 불일치) 시 최초 로그인 플로우로 전환하세요.
응답
{
"success": true,
"data": {
"valid": true,
"sub": 1,
"type": "app",
"game_id": 1,
"device_key": "android_abcdef-1234-...",
"iat": 1761714925,
"exp": 4825056125
}
}서버에서 JWT payload 전체를 반환하므로, 게임 클라이언트는 sub·game_id·device_key를 활용해 추가 검증/로그 기록에 사용할 수 있습니다.
⚠️ 보안 주의사항
게임 시작 시에는 반드시 토큰 검증 API를 호출해야 합니다. 토큰만으로는 게임 시작이 불가능하며, 서버에서 토큰의 유효성을 확인한 후에만 게임을 시작할 수 있습니다.
// ❌ 잘못된 방법 - 토큰만으로 게임 시작
if (!string.IsNullOrEmpty(accessToken))
{
StartGame(); // 보안 위험!
}
// ✅ 올바른 방법 - 토큰 검증 후 게임 시작
if (!string.IsNullOrEmpty(accessToken))
{
// 반드시 토큰 검증 API 호출
// VerifyTokenAndStartGame(); (추가될 경우 사용)
}🔒 기기별 보안 강화
JWT 토큰 생성 시 기기 고유 정보를 조합하여 특정 기기에서만 사용 가능합니다.
Android
디바이스 ID를 key 파라미터로 전달
인게임 클라이언트
- • 토큰 타입:
type: "app" - • 사용 예시: Unity 앱, 모바일 앱, 인게임
오류 코드
| 코드 | 상태 | 설명 |
|---|---|---|
| 400 | Bad Request | 잘못된 요청 파라미터 |
| 401 | Unauthorized | 인증 실패 또는 토큰 만료 |
| 403 | Forbidden | 접근 권한 없음 |
| 404 | Not Found | 요청한 리소스를 찾을 수 없음 |
| 500 | Internal Server Error | 서버 내부 오류 |
샘플 코드
↑ 페이지 최상단으로Unity C# - 인게임 통합
주요 기능
- • 딥링크 처리 (OAuth 인증 완료 후)
- • JWT 토큰 파싱 및 사용자 정보 추출
- • 토큰 유무 확인 및 게임 시작 로직
- • 영구 토큰 기반 인게임 로그인
핵심 코드
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class GameAuthManager : MonoBehaviour
{
private string accessToken;
private string deviceId;
void Start()
{
// 기기 고유 키 수집 (플랫폼별로 적절히 대체 가능)
deviceId = GetDeviceKey();
// 딥링크 이벤트 리스너 등록
Application.deepLinkActivated += OnDeepLinkActivated;
// 앱 시작 시 딥링크 확인
if (!string.IsNullOrEmpty(Application.absoluteURL))
{
OnDeepLinkActivated(Application.absoluteURL);
}
else
{
StartGame();
}
}
private string GetDeviceKey()
{
#if UNITY_ANDROID && !UNITY_EDITOR
// Android: 기기 ID 사용(예시)
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject contentResolver = currentActivity.Call<AndroidJavaObject>("getContentResolver");
AndroidJavaObject settingsSecure = new AndroidJavaClass("android.provider.Settings$Secure");
string androidId = settingsSecure.CallStatic<string>("getString", contentResolver, "android_id");
return androidId;
#else
return SystemInfo.deviceUniqueIdentifier;
#endif
}
// OAuth 인증 시작 - 최초 로그인
public void StartOAuthAuth(bool isSandbox = false, string sandboxGameId = "")
{
string clientSecret = "YOUR_CLIENT_SECRET"; // 게임 발급시 부여 받은 시크릿키
string loginUrl;
if (isSandbox)
{
// 샌드박스 환경
loginUrl = $"https://dev-sandbox.fetamix.com:9090/ingame-login?client_secret={clientSecret}&key={deviceId}&sandbox_game_id={sandboxGameId}";
}
else
{
// 라이브 환경
loginUrl = $"https://dev.fetamix.com:8081/ingame-login?client_secret={clientSecret}&key={deviceId}&client=game";
}
Application.OpenURL(loginUrl);
}
// 딥링크 처리 - 로그인 완료 후
private void OnDeepLinkActivated(string url)
{
if (url.StartsWith("fetamix://ingame-login"))
{
var uri = new System.Uri(url);
var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
string token = query["token"];
if (!string.IsNullOrEmpty(token))
{
accessToken = token;
Debug.Log("로그인 성공: JWT 토큰 수신");
StartGame();
}
}
}
// 게임 시작 - 토큰 확인
private void StartGame()
{
if (string.IsNullOrEmpty(accessToken))
{
Debug.Log("최초 로그인: OAuth 로그인 시작");
StartOAuthAuth();
}
else
{
Debug.Log("인게임 로그인: 토큰 검증 후 게임 시작");
StartCoroutine(VerifyTokenAndStartGame());
}
}
private IEnumerator VerifyTokenAndStartGame(bool isSandbox = false, string sandboxGameId = "")
{
string url = isSandbox
? "https://dev-api-sandbox.fetamix.com/api/v1/game/auth/verify"
: "https://dev-api.fetamix.com/api/v1/game/auth/verify";
using (UnityWebRequest req = UnityWebRequest.Get(url))
{
req.SetRequestHeader("Authorization", $"Bearer {accessToken}");
yield return req.SendWebRequest();
if (req.result == UnityWebRequest.Result.Success)
{
Debug.Log("토큰 검증 성공");
// TODO: 실제 게임 진입 로직
}
else
{
Debug.LogWarning($"토큰 검증 실패: {req.responseCode}");
StartOAuthAuth(isSandbox, sandboxGameId);
}
}
}
}API 호출 예시
토큰 검증 API
라이브 환경:
// Unity에서 토큰 검증 (라이브)
public IEnumerator VerifyToken()
{
string url = "https://dev-api.fetamix.com/api/v1/game/auth/verify";
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.SetRequestHeader("Authorization", $"Bearer {accessToken}");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
Debug.Log("토큰 검증 성공");
}
else
{
Debug.LogError("토큰 검증 실패");
}
}
}샌드박스 환경:
// Unity에서 토큰 검증 (샌드박스)
public IEnumerator VerifyToken()
{
string url = "https://dev-api-sandbox.fetamix.com/api/v1/game/auth/verify";
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.SetRequestHeader("Authorization", $"Bearer {accessToken}");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
Debug.Log("토큰 검증 성공");
}
else
{
Debug.LogError("토큰 검증 실패");
}
}
}※ 게임 번호는 추후 사용 중지 됩니다
게임 번호(game_id) 파라미터는 더 이상 사용하지 않으며, 클라이언트 시크릿(client_secret)을 사용하세요.