게임 서버를 운영하다 보면 Google API를 호출해야 할 일이 많다.
영수증 검증, 환불 처리, 구독 관리 등이 여기에 해당한다.
이 API들은 OAuth 2.0 인증이 필요하며, 처음 접하면 인증 흐름이 복잡하게 느껴질 수 있다.
서버에서 Google API를 호출하기 위한 인증 체계를 정리한다.
특히 Service Account를 활용한 서버 간 인증에 집중한다.
1. 게임 서버에서 자주 쓰는 Google API
영수증 조회 API
GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}인앱 결제 영수증이 유효한지 확인한다.
환불 API
POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/orders/{orderId}:refund특정 주문을 환불 처리한다.
최근 환불 조회 API
GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/voidedpurchases최근에 환불된 영수증 목록을 조회한다.
어뷰징 탐지에 유용하다.
2. OAuth 2.0 인증 플로우
Google API는 OAuth 2.0 프로토콜로 인증한다.
상황에 따라 여러 플로우가 있는데, 서버 간 통신에는 Service Account 기반의 JWT Bearer Flow를 쓴다.
Authorization Code Flow (프론트엔드 + 백엔드)
소셜 로그인(구글 로그인)에서 주로 사용한다:
JWT Bearer Flow (서버 간)
Service Account를 사용하는 서버 간 통신이다:
게임 서버에서 Google API를 호출할 때는 두 번째 플로우를 사용한다.
3. Google Cloud Service Account란?
Service Account는 사람이 아닌 프로그램이 인증을 수행하는 용도의 특별한 계정이다.
일반 Gmail 계정과 달리 비밀번호 대신 Private Key로 신원을 증명하고, 사용자 동의 화면 없이 토큰을 발급받는다.
권한도 특정 프로젝트나 리소스 단위로 부여할 수 있다.
Service Account 인증 파일
{
"type": "service_account",
"project_id": "my-game-project",
"private_key_id": "abc123...",
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
"client_email": "payment@my-game-project.iam.gserviceaccount.com",
"client_id": "123456789",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/..."
}이 파일은 서버에 안전하게 보관하고 API 호출에 사용한다.
4. JWT Bearer Token Flow
Service Account로 Access Token을 발급받는 과정을 JWT Bearer Token Flow라고 한다.
먼저 Service Account 인증 파일의 정보로 JWT를 만든다:
{
"iss": "payment@my-game-project.iam.gserviceaccount.com",
"aud": "https://oauth2.googleapis.com/token",
"scope": "https://www.googleapis.com/auth/androidpublisher",
"iat": 1742860800,
"exp": 1742864400
}iss: client_email (발급자)aud: token_uri (토큰 요청 URL)scope: 호출할 API의 권한 범위
JWT는 RS256 알고리즘으로 private_key를 사용해 서명한다.
생성한 JWT를 Google OAuth 서버에 제출한다:
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion={JWT}Google은 JWT의 서명을 검증하고 Access Token을 반환한다:
{
"access_token": "ya29.a0...",
"token_type": "Bearer",
"expires_in": 3600
}이제 발급받은 토큰을 Authorization 헤더에 담아 API를 호출하면 된다:
GET https://androidpublisher.googleapis.com/...
Authorization: Bearer ya29.a0...5. 코드로 구현하기 (C#)
Google.Apis 패키지 사용
using Google.Apis.Auth.OAuth2;
using Google.Apis.AndroidPublisher.v3;
using Google.Apis.Services;
public class GoogleApiService
{
private readonly AndroidPublisherService _publisherService;
public GoogleApiService(string serviceAccountKeyPath)
{
// Service Account 인증 파일 로드
var credential = GoogleCredential
.FromFile(serviceAccountKeyPath)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
// Android Publisher 서비스 초기화
_publisherService = new AndroidPublisherService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "MyGameServer"
});
}
public async Task<ProductPurchase> GetPurchaseAsync(
string packageName,
string productId,
string purchaseToken)
{
var request = _publisherService.Purchases.Products.Get(
packageName,
productId,
purchaseToken);
return await request.ExecuteAsync();
}
}사용 예시
var googleApi = new GoogleApiService("/secrets/service-account.json");
var purchase = await googleApi.GetPurchaseAsync(
"com.mygame.app",
"gem_100",
"token_abc123...");
if (purchase.PurchaseState == 0) // Purchased
{
// 상품 지급 처리
}6. Shell에서 테스트하기
개발/디버깅 시 Shell에서 직접 API를 호출할 수 있다.
gcloud CLI 설치 및 인증
# Service Account 인증
gcloud auth activate-service-account --key-file=./service-account.json
# 현재 인증된 계정 확인
gcloud auth listAccess Token 발급
# scope를 지정하여 토큰 발급
ACCESS_TOKEN=$(gcloud auth print-access-token \
--scopes=https://www.googleapis.com/auth/androidpublisher)토큰 정보 확인
curl "https://oauth2.googleapis.com/tokeninfo?access_token=$ACCESS_TOKEN"응답에서 scope에 androidpublisher가 포함되어 있는지 확인한다.
API 호출 테스트
# 환불 API 호출 예시
curl -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
"https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.mygame.app/orders/GPA.1234-5678-9012:refund"7. 주의사항
Access Token은 보통 1시간 동안 유효하다.
매 요청마다 새로 발급하지 말고 캐싱해서 재사용한다.
Google.Apis 패키지를 쓰면 토큰 갱신을 자동으로 처리해준다.
JWT를 생성할 때는 필요한 scope만 지정한다.
과도한 권한은 그 자체가 보안 위험이다.
마무리
Service Account의 Private Key로 서명한 JWT를 Access Token으로 교환하고, 그 토큰으로 API를 호출한다.
Google Play Developer API뿐 아니라 Google Cloud의 다른 API들도 같은 방식으로 호출할 수 있다.
Cloud Storage, BigQuery 등도 동일한 인증 체계를 사용한다.