인증 헤더 만들기

REST API 요청 포맷

REST API는 HTTP를 통해 호출이 이루어집니다.

POST, PUT, DELETE 요청에 body가 존재하는 경우 JSON 형식으로 파라미터를 전송해야 합니다.
유효한 컨텐츠 타입의 예시는 다음과 같으며, 각 프로그래밍 언어 라이브러리에 따라 약간의 차이가 있을 수 있습니다.

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

JWT 인증 토큰 만들기

REST API 요청시, 발급받은 API KeySecret Key로 토큰을 생성하여 Authorization 헤더를 통해 전송합니다. 토큰은 JWT(https://jwt.io) 형식을 따릅니다.

서명 방식은 HS256 을 권장하며, 서명에 사용할 Secret은 발급받은 Secret Key를 사용합니다.
페이로드의 구성은 다음과 같습니다.

Private API 요청 시 발급받은 API KeySecret Key를 이용하여 5개의 파라미터를 헤더에 추가하여 전송합니다.

요청 변수설명타입
access_key사용자 API KeyString / 필수
nonce무작위의 UUID 문자열String / 필수
timestamp현재의 시간을 밀리초 (millisecond, ms)로 표현한 값
(예 : 1655280216476)
Number / 필수
query_hash해싱된 query string (파라미터가 있을 경우 필수)String / 옵션
query_hash_algquery_hash를 생성하는 데에 사용한 알고리즘 (기본값 : SHA512)String / 옵션

생성된 인증 헤더의 페이로드 예시입니다.

{
  "access_key": "L7rVaYfBIc2BDsnlQGfkR93d6DoOAJCw7mJr5Eso",
  "nonce": "6f5570df-d8bc-4daf-85b4-976733feb624",
  "timestamp": 1712230310689,
  "query_hash": "1c2362ca9d79947582cae192acf63efb8756caa49af1eb64b12ba45617165431a3dd3e47d0476bc2a347b7a1ea512db7f316f56144084b1493166e3c9113a8eb",
  "query_hash_alg": "SHA512"
}

(예시) 파라미터가 없을 경우

const jwt = require('jsonwebtoken')
const { v4: uuidv4 } = require('uuid')

const accessKey = '발급받은 API KEY'
const secretKey = '발급받은 SECRET KEY'

const payload = {
    access_key: accessKey,
    nonce: uuidv4(),
    timestamp: Date.now()
};

console.log(payload);

const jwtToken = jwt.sign(payload, secretKey)
const authorizationToken = `Bearer ${jwtToken}`

console.log(authorizationToken);
# Python 3
# pip3 installl pyJwt
import jwt 
import uuid
import time

accessKey = "발급받은 API KEY"
secretKey = "발급받은 SECRET KEY"

payload = {
    'access_key': accessKey,
    'nonce': str(uuid.uuid4()),
    'timestamp': round(time.time() * 1000)
}

print(payload, "\n")
    
jwt_token = jwt.encode(payload, secretKey)
authorization_token = 'Bearer {}'.format(jwt_token)

print(authorization_token)
// https://mvnrepository.com/artifact/com.auth0/java-jwt
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

import java.util.UUID;

public class OpenAPIAuthSampleNoArgs {

    public static void main(String[] args) {
        String accessKey = "발급받은 API KEY";
        String secretKey = "발급받은 SECRET KEY";

        Algorithm algorithm = Algorithm.HMAC256(secretKey);

        String jwtToken = JWT.create()
                .withClaim("access_key", accessKey)
                .withClaim("nonce", UUID.randomUUID().toString())
                .withClaim("timestamp", System.currentTimeMillis())
                .sign(algorithm);

        String authenticationToken = "Bearer " + jwtToken;

        System.out.println(authenticationToken);
    }
}

(예시) 파라미터가 있는 경우

HTTP 쿼리 문자열, 혹은 body를 통해 파라미터를 전달하는 경우 모두 JWT 페이로드의 query_hash 값을 설정해야합니다.

파라미터의 자료형 중 배열이 존재하는 경우, 올바른 query string의 형태는 다음과 같습니다.

key[]=value1&key[]=value2 ...

이와 다른 형태로 요청하면 토큰 검증에 실패할 수 있으니 유의하시기 바랍니다.

const jwt = require('jsonwebtoken');
const { v4: uuidv4 } = require('uuid');
const crypto = require('crypto');
const querystring = require('querystring');

const accessKey = '발급받은 API KEY'
const secretKey = '발급받은 SECRET KEY'

// GET (query parameters)
// const query = 'string=abc&number=123'
// POST (request body)
const query = querystring.encode({
    string: 'abc',
    number: 123
})

const alg = 'SHA512'
const hash = crypto.createHash(alg)
const queryHash = hash.update(query, 'utf-8').digest('hex')

const payload = {
    access_key: accessKey,
    nonce: uuidv4(),
    timestamp: Date.now(),
    query_hash: queryHash,
    query_hash_alg: alg
};

console.log(payload);

const jwtToken = jwt.sign(payload, secretKey)
const authorizationToken = `Bearer ${jwtToken}`

console.log(authorizationToken);
# Python 3
# pip3 installl pyJwt
import jwt 
import uuid
import hashlib
import time
from urllib.parse import urlencode

accessKey = "발급받은 API KEY"
secretKey = "발급받은 SECRET KEY"

# GET (query parameters)
# query = 'string=abc&number=123'.encode()
# POST (request body)
query = urlencode(dict( string="abc", number=123 )).encode()

hash = hashlib.sha512()
hash.update(query)
query_hash = hash.hexdigest()

payload = {
    'access_key': accessKey,
    'nonce': str(uuid.uuid4()),
    'timestamp': round(time.time() * 1000), 
    'query_hash': query_hash,
    'query_hash_alg': 'SHA512',
}

print(payload, "\n")
    
jwt_token = jwt.encode(payload, secretKey)
authorization_token = 'Bearer {}'.format(jwt_token)

print(authorization_token)
// https://mvnrepository.com/artifact/com.auth0/java-jwt
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
// https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class OpenAPIAuthSampleArgs {

    public static void main(String[] args) throws NoSuchAlgorithmException {
        
        String accessKey = "발급받은 API KEY";
        String secretKey = "발급받은 SECRET KEY";

        // GET (query parameters)
				// String query = "string=abc&number=123";
        // POST (request body)
        List<NameValuePair> queryParams = new ArrayList<>();
        queryParams.add(new BasicNameValuePair("string", "abc"));
        queryParams.add(new BasicNameValuePair("number", "123"));
        String query = URLEncodedUtils.format(queryParams, StandardCharsets.UTF_8);

        MessageDigest md = MessageDigest.getInstance("SHA-512");
        md.update(query.getBytes(StandardCharsets.UTF_8));

        String queryHash = String.format("%0128x", new BigInteger(1, md.digest()));

        Algorithm algorithm = Algorithm.HMAC256(secretKey);
        String jwtToken = JWT.create()
                .withClaim("access_key", accessKey)
                .withClaim("nonce", UUID.randomUUID().toString())
                .withClaim("timestamp", System.currentTimeMillis())
                .withClaim("query_hash", queryHash)
                .withClaim("query_hash_alg", "SHA512")
                .sign(algorithm);

        String authenticationToken = "Bearer " + jwtToken;

        System.out.println(authenticationToken);
    }
}