인증
팝빌 API를 사용하기 위한 공통 정의 사항과 인증 토큰 발급 및 사용 방법을 안내합니다.
1. 공통 정의 사항
섹션 제목: “1. 공통 정의 사항”팝빌 API 규격은 다음과 같이 정의합니다.
- RESTful API
- HTTPS 통신 / TLS 1.3, 1.2 지원
- JSON 메시지 포맷
API 호출과 응답에 필요한 문자 인코딩은 모두 UTF-8 Character Set 을 사용합니다.
팝빌 API에서 사용하는 Base URL은 다음과 같습니다.
| 환경 | Base URL | ServiceID |
|---|---|---|
| 팝빌 인증 서버 | https://auth.linkhub.co.kr | - |
| 팝빌 API 테스트 서버 | https://popbill-test.linkhub.co.kr | POPBILL_TEST |
| 팝빌 API 운영 서버 | https://popbill.linkhub.co.kr | POPBILL |
※ ServiceID는 팝빌 API 테스트/운영을 구별하는 고유식별정보입니다.
위 도메인의 IP는 가변적으로 변경됩니다.
방화벽으로 인해 고정 IP가 필요한 경우에는 아래의 Outbound 정보를 등록해야 합니다. 고정 IP를 설정한 뒤에는 아래의 안내된 도메인으로 호출해야 합니다.
| 환경 | Base URL | IP | PORT |
|---|---|---|---|
| 팝빌 인증 서버 | https://static-auth.linkhub.co.kr | 52.78.164.186 13.124.222.90 | 443 |
| 팝빌 API 테스트 서버 | https://static-popbill-test.linkhub.co.kr | 52.78.164.186 13.124.222.90 | 443 |
| 팝빌 API 운영 서버 | https://static-popbill.linkhub.co.kr | 52.78.164.186 13.124.222.90 | 443 |
2. 인증 방식
섹션 제목: “2. 인증 방식”팝빌 인증 방식은 팝빌 인증 서버로부터 토큰을 발급받고, 이후 모든 API 호출 시 발급받은 토큰을 함께 전송하는 방식입니다.
- 팝빌 인증 서버에서 토큰을 발급받으려면 HTTP
AuthorizationHeader에 다음 형식으로 인증 정보를 기재해야 합니다.
Authorization: LINKHUB {LinkID} {Signature}LinkID는 파트너를 식별하기 위한 값으로 팝빌에서 API Key 발급 시 제공됩니다. Signature는 요청 본문의 변조 방지를 위한 서명 값으로, API Key 발급 시 함께 제공되는 SecretKey를 이용해 HMAC-SHA256 알고리즘으로 생성합니다.
Signature 생성 방법은 다음과 같습니다.
// 팝빌에서 발급받은 API Key의 LinkIDString linkID = "TESTER";
// 팝빌에서 발급받은 API key의 SecretKeyString secretKey = "SwWxqU+0TErBXy/9TVjIPEnI0VTUMMSQZtJf3Ed8q3I=";
// 팝빌회원 사업자번호String accessID = "1234567890";
// 토큰 사용 허용 IP -> 요청 헤더 X-LH-Forwarded 에 사용String forwardedIP = "*";
// API 버전 -> 요청 헤더 X-LH-Version 에 사용String apiVersion = "2.0";
// 테스트 환경: POPBILL_TEST, 운영 환경 : POPBILLString serviceID = "POPBILL_TEST";
// Request BodyString requestBody = "{\"access_id\":\"" + accessID + "\", \"scope\":[\"110\", \"member\"]}";byte[] bodyBytes = requestBody.getBytes(StandardCharsets.UTF_8);
// BodyDigest (SHA-256 -> Base64 encode)byte[] sha256Bytes = MessageDigest.getInstance("SHA-256").digest(bodyBytes);String bodyDigest = Base64.getEncoder().encodeToString(sha256Bytes);
// 요청 일시(UTC) -> 요청 헤더 X-LH-Date 에 사용SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");sdf.setTimeZone(TimeZone.getTimeZone("UTC"));String requestDT = sdf.format(new Date());
// 요청 URIString resourceURI = "/" + serviceID + "/Token";
// StringToSign 구성String stringToSign = "POST" + "\n" + bodyDigest + "\n" + requestDT + "\n" + forwardedIP + "\n" + apiVersion + "\n" + resourceURI;
// SignatureMac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(Base64.getDecoder().decode(secretKey), "HmacSHA256"));
byte[] hmacBytes = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));String signature = Base64.getEncoder().encodeToString(hmacBytes);
// Authorization HeaderString authorization = "LINKHUB" + " " + linkID + " " + signature;bodyDigest: 요청 본문(Request Body)의 SHA-256 해시값을 Base64로 인코딩한 문자열입니다.requestDT: 요청 일시로, 반드시 UTC 시간으로 기재해야 합니다.forwardedIP: 토큰 사용을 허용할 IP를 의미하며, 미입력 시 인증 서버에 토큰 발급 요청을 보낸 IP에서만 사용할 수 있습니다. 모든 IP에서 API 호출을 허용하려면 *로 입력합니다.apiVersion: 팝빌 API 버전으로 2.0을 입력합니다.resourceURI: 토큰을 발급받을 API의 요청 URI로, /{serviceID}/Token 형식으로 구성합니다.stringToSign: HTTP Method,bodyDigest,requestDT,forwardedIP,apiVersion,resourceURI를 줄바꿈(\n)으로 연결한 문자열입니다.
stringToSign을 secretKey로 HMAC-SHA256 서명하고 Base64로 인코딩하면 signature가 생성됩니다. 생성된 signature를 Authorization Header에 입력하여 인증 토큰 발급을 요청합니다.
- 발급받은 인증 토큰은 팝빌 API를 호출할 때 권한을 검증하는데 사용됩니다. 토큰은 발급 시점부터 30분간 유효하며, 유효 기간이 지난 후에는 새 토큰을 재발급받아 사용해야 합니다.
팝빌 API를 호출할 때 Bearer 방식으로 Authorization Header에 토큰 값을 입력합니다.
Authorization: Bearer {session_token}3. 인증 토큰 발급
섹션 제목: “3. 인증 토큰 발급” https://auth.linkhub.co.kr/POPBILL_TEST/Token - 팝빌 API를 사용하기 위한 인증 토큰을 발급합니다.
인증 토큰은 사업자번호별로 별도 발급이 필요합니다.
토큰은 발급 시점부터 30분 동안만 유효하며, 만료시에는 새 토큰을 재발급받아야 합니다.
Request
요청 헤더
| 순번 | 변수명 | 필수 | 설명 |
|---|---|---|---|
| 1 | Authorization | Y | 인증 토큰 |
| 2 | Content-Type | Y | 요청 본문 형식
|
| 3 | X-LH-Version | Y | API 버전
|
| 4 | X-LH-Date | Y | 요청 일시(UTC) 형식 : yyyy-MM-ddTHH:mm:ssZ |
| 5 | X-LH-Forwarded | N | 토큰 사용 허용 IP
미입력: 토큰 발급을 요청한 IP에서만 토큰 사용 가능 |
요청 본문
| 순번 | 변수명 | 타입 | 길이 | 필수 | 설명 |
|---|---|---|---|---|---|
| 1 | access_id | string | 10 | Y | 팝빌회원 사업자번호 |
| 2 | scope | array | - | Y | API 접근 권한
|
요청 예시
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.nio.charset.StandardCharsets;import java.security.InvalidKeyException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.text.SimpleDateFormat;import java.util.Base64;import java.util.Date;import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
// 팝빌에서 발급받은 API Key의 LinkID String linkID = "TESTER";
// 팝빌에서 발급받은 API Key의 SecretKey String secretKey = "SwWxqU+0TErBXy/9TVjIPEnI0VTUMMSQZtJf3Ed8q3I=";
// 팝빌회원 사업자번호 String accessID = "1234567890";
// 토큰 사용 허용 IP -> 요청 헤더 X-LH-Forwarded에 사용 String forwardedIP = "*";
// API 버전 -> 요청 헤더 X-LH-Version에 사용 String apiVersion = "2.0";
// 테스트 환경: POPBILL_TEST, 운영 환경 : POPBILL String serviceID = "POPBILL_TEST";
// Request Body String requestBody = "{\"access_id\":\"" + accessID + "\", \"scope\":[\"110\", \"member\"]}"; byte[] bodyBytes = requestBody.getBytes(StandardCharsets.UTF_8);
// BodyDigest (SHA-256 -> Base64 encode) byte[] sha256Bytes = MessageDigest.getInstance("SHA-256").digest(bodyBytes); String bodyDigest = Base64.getEncoder().encodeToString(sha256Bytes);
// 요청 일시(UTC) -> 요청 헤더 X-LH-Date에 사용 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); String requestDT = sdf.format(new Date());
// 요청 URI String resourceURI = "/" + serviceID + "/Token";
// StringToSign 구성 String stringToSign = "POST" + "\n" + bodyDigest + "\n" + requestDT + "\n" + forwardedIP + "\n" + apiVersion + "\n" + resourceURI;
// Signature Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(Base64.getDecoder().decode(secretKey), "HmacSHA256"));
byte[] hmacBytes = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); String signature = Base64.getEncoder().encodeToString(hmacBytes);
// Authorization Header String authorization = "LINKHUB" + " " + linkID + " " + signature;
URL url = new URL("https://auth.linkhub.co.kr" + resourceURI); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Authorization", authorization); conn.setRequestProperty("x-lh-forwarded", forwardedIP); conn.setRequestProperty("x-lh-date", requestDT); conn.setRequestProperty("x-lh-version", apiVersion);
try (OutputStream os = conn.getOutputStream()) { os.write(bodyBytes); }
int status = conn.getResponseCode(); InputStream is = (status == HttpURLConnection.HTTP_OK) ? conn.getInputStream() : conn.getErrorStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buf = new byte[8192]; int n; while ((n = is.read(buf)) != -1) { baos.write(buf, 0, n); } is.close();
String responseBody = new String(baos.toByteArray(), StandardCharsets.UTF_8);
System.out.println("Body : " + responseBody); }}Response
응답 본문
| 순번 | 변수명 | 타입 | 길이 | 설명 |
|---|---|---|---|---|
| 1 | session_token | string | - | 인증 토큰 |
| 2 | serviceID | string | - | 테스트/운영 환경 구분 고유식별정보
|
| 3 | linkID | string | - | LinkID |
| 4 | userID | string | - | 팝빌회원 사업자번호 |
| 5 | partnerCode | string | - | 파트너코드 |
| 6 | usercode | string | - | 팝빌회원 코드 |
| 7 | scope | array | - | API 접근 권한
|
| 8 | ipaddress | string | - | 토큰 사용 허용 IP |
| 9 | expiration | string | - | 토큰 만료일시(UTC) 형식 : yyyy-MM-ddTHH:mm:ssZ |
응답 예시
{ "session_token": "dGfY0osTAoWNdlNwmugjEDTu...4MuWhVplgLrlQ7FzenX98qiZYDSqQ0ISEOJP", "serviceID": "POPBILL_TEST", "linkID": "TESTER", "userID": "1234567890", "partnerCode": "014040000003", "usercode": "025070002467", "scope": [ "member", "110" ], "ipaddress": "*", "expiration": "2025-11-19T03:41:17.839Z"}