---
title: 오픈 API 사용을 위한 JWT 인증 토큰 만들기
slug: world-sdk-guide-kr/api-jwt
docTags: 
createdAt: 2024-09-02T08:34:13.134Z
---

## 오픈 API 요청 형식

ZEPETO 오픈 API는 HTTP를 통해 호출됩니다.

요청에 본문이 포함된 경우, 매개변수는 JSON 형식으로 전송해야 합니다.
유효한 콘텐츠 유형의 예는 아래에 표시되어 있으며, 각 프로그래밍 언어 라이브러리에 따라 약간의 차이가 있을 수 있습니다.

```http
Content-Type: application/json; charset=utf-8
```



## ZEPETO 스튜디오에서 액세스 키 및 비밀 키 받기

JWT 인증 토큰을 생성하기 전에 ZEPETO 스튜디오 콘솔에서 액세스 키와 비밀 키를 받아야 합니다.

:::hint{type="info"}
**📘&#x20;**&#xB2E4;음 가이드를 참조하십시오. [오픈 API 관리하기](docId:-1WN8_R5f0k_2BKRwZIG5)&#x20;
:::



## JWT 인증 토큰 생성하기

ZEPETO 오픈 API는 액세스 키와 비밀 키를 기반으로 JWT([https://jwt.io](https://jwt.io)) 형식의 토큰을 생성하고 이를 Authorization 헤더에 전송합니다.

서명 방법으로 HS256을 권장하며, 서명에 사용할 비밀은 발급된 비밀 키입니다.

JWT 토큰 페이로드는 다음 형식을 가집니다:

:::CodeblockTabs
JWT 토큰 페이로드

```java
{
    "access_key": "발급된 액세스 키 (필수)",
    "nonce": "무작위 UUID 값 (필수)",
    "uri_hash": "쿼리 매개변수를 포함한 URI의 해시 값, 기본 경로는 제외 (필수)",
    "body_hash": "요청 본문의 해시 값"
}
```
:::



- uri\_hash는 기본 경로를 제외한 쿼리 매개변수를 포함한 uri의 해시 값입니다.
- body\_hash는 요청 본문이 존재할 때만 페이로드에 삽입되도록 json 문자열로 변환된 값이며, 요청 본문이 없으면 생략됩니다.
  - 이 경우 json 문자열의 키와 값 사이에 공백이 없어야 합니다.
- uri\_hash와 body\_hash는 요청에 전송된 쿼리 매개변수 및 요청 본체와 동일한 값으로 해시되어야 합니다. (값의 순서도 동일해야 합니다.)

:::hint{type="danger"}
* API 호출 수 제한: 1분에 최대 300회 호출 가능합니다.
:::



## 요청 본문이 없을 때의 예

사용하려는 API에 따라 액세스 키, 비밀 키, 월드 ID, URI 및 쿼리 매개변수를 입력하십시오.

아래의 예제 코드는 DataStorage 카테고리의 플레이어 데이터 API를 기반으로 작성되었습니다.

### 자바

```java
String accessKey = "accessKey";
String secretKey = "secretKey";
 
String worldId = "com.test.world";
String uri = "/datastorage/v1/worlds/" + worldId + "/player-data";
 
MessageDigest uriHash = MessageDigest.getInstance("SHA-256");
uriHash.update(uri.getBytes(StandardCharsets.UTF_8));
byte[] uriHashBytes = uriHash.digest();
 
ObjectMapper objectMapper = new ObjectMapper();
 
Map<String, Object> payload = new HashMap<>();
payload.put("access_key", accessKey);
payload.put("nonce", UUID.randomUUID().toString());
payload.put("uri_hash", new String(Base64.encodeBase64(uriHashBytes), StandardCharsets.UTF_8));
 
String jwtToken = Jwts.builder()
                    .setPayload(objectMapper.writeValueAsString(payload))
                    .signWith(SignatureAlgorithm.HS256, secretKey.getBytes(StandardCharsets.UTF_8))
                    .compact();
 
String authorization = "Bearer " + jwtToken;
```



### 파이썬

```python
import jwt
import uuid
import hashlib
import base64
 
accessKey = 'accessKey'
secretKey = 'secretKey'
 
worldId = 'com.test.world'
uri = '/datastorage/v1/worlds/' + worldId + '/player-data?playerId=testplayerid&keys=test'
hash = hashlib.sha256()
hash.update(uri.encode())
 
payload = {
    'access_key': accessKey,
    'nonce': str(uuid.uuid4()),
    'uri_hash': base64.b64encode(hash.digest()).decode('utf8')
}
 
jwt_token = jwt.encode(payload, secretKey)
authorization = 'Bearer {}'.format(jwt_token)
```



### NodeJS

```typescript
import * as jwt from 'jsonwebtoken';
import * as uuid from 'uuid';
import * as crypto from 'crypto-js';
import { Buffer } from 'safe-buffer';

const accessKey = 'accessKey';
const secretKey = 'secretKey';
const worldId = 'com.test.world';
const uri = '/datastorage/v1/worlds/' + worldId + '/player-data?playerId=testplayerid&keys=test';
const hash = crypto.SHA256(uri);

const payload = {
  access_key: accessKey,
  nonce: uuid.v4(),
  uri_hash: Buffer.from(hash.toString(), 'hex').toString('base64')
};
const jwtToken = jwt.sign(payload, secretKey);
const authorization = `Bearer ${jwtToken}`;

```



## 요청 본문이 있는 경우의 예

사용하려는 API에 따라 액세스 키, 비밀 키, 월드 ID, URI 및 본문 매개변수를 입력하십시오.

아래의 예제 코드는 DataStorage 카테고리의 Set Player Data API를 기반으로 작성되었습니다.

### 자바

```java
String accessKey = "accessKey";
String secretKey = "secretKey";
 
String worldId = "com.test.world";
String uri = "/datastorage/v1/worlds/" + worldId + "/player-data";
 
MessageDigest uriHash = MessageDigest.getInstance("SHA-256");
uriHash.update(uri.getBytes(StandardCharsets.UTF_8));
byte[] uriHashBytes = uriHash.digest();
 
ObjectMapper objectMapper = new ObjectMapper();
 
PlayerData dataMap = new PlayerData("test", "test value");
 
List<PlayerData> dataList = new ArrayList<>();
dataList.add(dataMap);
 
PlayerDataSetParam param = new PlayerDataSetParam(dataList, "testplayerid");
 
 
MessageDigest paramHash = MessageDigest.getInstance("SHA-256");
paramHash.update(objectMapper.writeValueAsString(param).getBytes(StandardCharsets.UTF_8));
byte[] paramHashBytes = paramHash.digest();
 
Map<String, Object> payload = new HashMap<>();
payload.put("access_key", accessKey);
payload.put("nonce", UUID.randomUUID().toString());
payload.put("uri_hash", new String(Base64.encodeBase64(uriHashBytes), StandardCharsets.UTF_8));
payload.put("body_hash", new String(Base64.encodeBase64(paramHashBytes), StandardCharsets.UTF_8));
 
String jwtToken = Jwts.builder()
                    .setPayload(objectMapper.writeValueAsString(payload))
                    .signWith(SignatureAlgorithm.HS256, secretKey.getBytes(StandardCharsets.UTF_8))
                    .compact();
 
String authorization = "Bearer " + jwtToken;
```



### 파이썬

```python
import jwt
import uuid
import hashlib
import base64
import simplejson as json
 
accessKey = 'accessKey' secretKey = 'secretKey'
 
worldId = 'com.test.world'
uri = '/datastorage/v1/worlds/' + worldId + '/player-data'
hash = hashlib.sha256()
hash.update(uri.encode())
 
param = {
    'playerId': 'testplayerid',
    'data':[
        {
            'key': 'test',
            'value': 'test value'
        }
    ]
}
 
param_hash = hashlib.sha256()
param_hash.update(json.dumps(param, ensure_ascii=False, encoding='surrogatepass').encode())
 
payload = {
    'access_key': accessKey,
    'nonce': str(uuid.uuid4()),
    'uri_hash': base64.b64encode(hash.digest()).decode('utf8'),
    'body_hash': base64.b64encode(param_hash.digest()).decode('utf8')
}
 
jwt_token = jwt.encode(payload, secretKey)
authorization = 'Bearer {}'.format(jwt_token)
```



### NodeJS

```typescript
import * as jwt from 'jsonwebtoken';
import * as uuid from 'uuid';
import * as crypto from 'crypto-js';
import { Buffer } from 'safe-buffer';

const accessKey = 'accessKey';
const secretKey = 'secretKey';
const worldId = 'com.test.world';
const uri = '/datastorage/v1/worlds/' + worldId + '/player-data';
const hash = crypto.SHA256(uri);

const param = {
  playerId: 'testplayerid',
  data: [
    {
      value: 'test value',
      key: 'test'
    }
  ]
};
const paramHash = crypto.SHA256(JSON.stringify(param,null,0));

const payload = {
  access_key: accessKey,
  nonce: uuid.v4(),
  uri_hash: Buffer.from(hash.toString(), 'hex').toString('base64'),
  body_hash: Buffer.from(paramHash.toString(), 'hex').toString('base64')
};
const jwtToken = jwt.sign(payload, secretKey);
const authorization = `Bearer ${jwtToken}`;
```



##

:::hint{type="danger"}
❗️ **주의**

- OpenAPI는 별도의 웹 또는 앱에서 사용하기 위해 제공되는 기능입니다.
- 현재 ZEPETO 서버 스크립트는 ZEPETO Open API 호출을 할 수 없습니다.
- ZEPETO 멀티플레이어에서 Open API 호출을 하려면 다음 방법을 제안합니다:
  - Open API와 통신하여 필요한 비즈니스 로직을 수행하기 위해 별도의 서버를 설정합니다.
  - ZEPETO 서버에서 httpService 패키지를 사용하여 설정한 서버와 직접 통신합니다.
  - HTTP Authorize 헤더를 사용하는 것과 같은 상대적으로 간단한 인증 방법을 구현하여 ZEPETO 서버에서 지원하는 기능 내에서 호출을 가능하게 합니다.
:::

