«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

올해는 머신러닝이다.

Node로 인앱 결제 구독 검증 방법 본문

스터디/Node Js

Node로 인앱 결제 구독 검증 방법

행복한 수지아빠 2025. 2. 16. 19:42

Node.js로 인앱 결제 구독 검증하는 방법

Google Play 및 App Store의 구독 결제를 검증하려면 서버에서 영수증을 확인하는 API를 호출해야 해.
이를 Node.js 기반으로 구현하는 방법을 단계별로 설명할게.


---

1. 검증이 필요한 이유

보안 강화: 클라이언트에서 결제 정보를 조작할 가능성을 방지

자동 갱신 확인: 구독이 유지되는지 검증하여 액세스 관리

환불 및 취소 확인: 유저가 환불받았는지 체크 가능



---

2. Google Play 구독 검증

Google의 Google Play Developer API를 사용하여 구독 상태를 검증해야 해.

(1) Google API 활성화

1. Google Cloud Console에서 프로젝트 생성


2. Google Play Android Developer API 활성화


3. OAuth 2.0 서비스 계정 생성 및 JSON 키 다운로드


4. Google Play Console에서 서비스 계정 권한 추가

"구매 항목 조회" 권한 부여

"재무 데이터 보기" 권한 부여





---

(2) Google API 요청을 위한 인증 설정

Google API를 호출하려면 서비스 계정 JSON 키를 사용해야 해.
Node.js에서 google-auth-library 패키지를 이용해 인증할 수 있어.

npm install google-auth-library axios express

const { google } = require("google-auth-library");
const axios = require("axios");
const fs = require("fs");

// 서비스 계정 키 파일 로드
const KEY_FILE_PATH = "path/to/your-service-account.json";
const PACKAGE_NAME = "com.example.app"; // 앱의 패키지명

// Google API 인증 함수
async function getAccessToken() {
    const auth = new google.auth.GoogleAuth({
        keyFile: KEY_FILE_PATH,
        scopes: ["https://www.googleapis.com/auth/androidpublisher"],
    });

    const client = await auth.getClient();
    const accessToken = await client.getAccessToken();
    return accessToken.token;
}


---

(3) 구독 검증 API 요청

구매자가 구독을 했는지 확인하려면 purchases.subscriptions.get 엔드포인트를 호출해야 해.


async function verifyAndroidSubscription(purchaseToken) {
    const accessToken = await getAccessToken();
    const url = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PACKAGE_NAME}/purchases/subscriptions/premium_subscription/tokens/${purchaseToken}`;

    try {
        const response = await axios.get(url, {
            headers: {
                Authorization: `Bearer ${accessToken}`,
            },
        });

        return response.data;
    } catch (error) {
        console.error("구독 검증 실패:", error.response ? error.response.data : error.message);
        return null;
    }
}

(4) 응답 데이터 해석

Google Play API에서 반환하는 응답 예제:

{
  "startTimeMillis": "1614764800000",
  "expiryTimeMillis": "1617366800000",
  "autoRenewing": true,
  "priceAmountMicros": "4990000",
  "priceCurrencyCode": "USD",
  "paymentState": 1
}

expiryTimeMillis: 구독 만료 시간 (이 시간이 지나면 액세스를 중단해야 함)

autoRenewing: 자동 갱신 여부 (false면 사용자가 구독을 취소한 상태)

paymentState:

0: 결제 대기

1: 결제 완료

2: 무료 체험 기간

3: 보류 상태




---

3. App Store 구독 검증

Apple의 App Store Server API를 이용해 구독 상태를 확인할 수 있어.

(1) Apple API 활성화

1. Apple Developer Portal에서 App Store Server API 키 생성

App Store Connect → Users and Access → Keys에서 생성

Key ID, Issuer ID, Private Key 다운로드



2. bundleId 확인 (예: com.example.app)




---

(2) Apple API 요청을 위한 JWT 토큰 생성

Apple API를 호출하려면 JWT(JSON Web Token)를 사용해야 해.
jsonwebtoken 패키지를 설치하고 JWT를 생성하자.

npm install jsonwebtoken axios

const jwt = require("jsonwebtoken");
const fs = require("fs");

// Apple API 인증 정보
const APPLE_KEY_ID = "YOUR_KEY_ID";
const APPLE_ISSUER_ID = "YOUR_ISSUER_ID";
const APPLE_BUNDLE_ID = "com.example.app";
const APPLE_PRIVATE_KEY_PATH = "path/to/AuthKey.p8";

// JWT 생성 함수
function generateAppleJWT() {
    const privateKey = fs.readFileSync(APPLE_PRIVATE_KEY_PATH, "utf8");

    const token = jwt.sign(
        {
            iss: APPLE_ISSUER_ID,
            iat: Math.floor(Date.now() / 1000),
            exp: Math.floor(Date.now() / 1000) + 60 * 10, // 10분 유효
            aud: "appstoreconnect-v1",
            bid: APPLE_BUNDLE_ID,
        },
        privateKey,
        {
            algorithm: "ES256",
            keyid: APPLE_KEY_ID,
        }
    );

    return token;
}


---

(3) Apple API 요청 (영수증 검증)

async function verifyAppleSubscription(receiptData) {
    const jwtToken = generateAppleJWT();
    const url = "https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions/";

    try {
        const response = await axios.post(url, {
            "receipt-data": receiptData,
        }, {
            headers: {
                Authorization: `Bearer ${jwtToken}`,
                "Content-Type": "application/json",
            },
        });

        return response.data;
    } catch (error) {
        console.error("Apple 구독 검증 실패:", error.response ? error.response.data : error.message);
        return null;
    }
}


---

(4) 응답 데이터 해석

Apple의 응답 예제:

{
  "latest_receipt_info": [
    {
      "expires_date_ms": "1617366800000",
      "is_trial_period": "false",
      "status": "active"
    }
  ]
}

expires_date_ms: 구독 만료 시간

is_trial_period: 무료 체험 여부

status: "active"이면 구독 중, "expired"이면 구독이 만료됨



---

4. 전체적인 API 구현 (Express 서버)

이제 검증 API를 Express 서버로 만들어 보자.

const express = require("express");
const app = express();

app.use(express.json());

// Android 구독 검증 API
app.post("/verify/android", async (req, res) => {
    const { purchaseToken } = req.body;
    if (!purchaseToken) return res.status(400).json({ error: "purchaseToken이 필요합니다." });

    const result = await verifyAndroidSubscription(purchaseToken);
    res.json(result);
});

// iOS 구독 검증 API
app.post("/verify/ios", async (req, res) => {
    const { receiptData } = req.body;
    if (!receiptData) return res.status(400).json({ error: "receiptData가 필요합니다." });

    const result = await verifyAppleSubscription(receiptData);
    res.json(result);
});

// 서버 실행
app.listen(3000, () => console.log("서버 실행 중 (포트 3000)"));


---

결론

Google Play는 purchases.subscriptions.get API를 사용하여 구독을 검증

App Store는 storekit-sandbox.itunes.apple.com을 통해 JWT 인증 후 영수증 검증

Express 서버를 사용해 API를 구축하면 클라이언트에서 직접 검증하는 것보다 보안이 강화됨


이제 인앱 결제 구독 검증을 Node.js로 구현할 수 있어!